@praxisui/page-builder 8.0.0-beta.99 → 9.0.0-beta.1

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.
@@ -7,7 +7,7 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
7
7
  import * as i2$1 from '@angular/material/icon';
8
8
  import { MatIconModule } from '@angular/material/icon';
9
9
  import * as i2$2 from '@praxisui/core';
10
- import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, providePraxisI18n, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, deepMerge, generateId, ComponentMetadataRegistry, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
10
+ import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, providePraxisI18n, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, deepMerge, generateId, ComponentMetadataRegistry, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
11
11
  export { WidgetShellComponent } from '@praxisui/core';
12
12
  import * as i3 from '@angular/material/tooltip';
13
13
  import { MatTooltipModule } from '@angular/material/tooltip';
@@ -25,13 +25,13 @@ import * as i6 from '@angular/material/divider';
25
25
  import { MatDividerModule } from '@angular/material/divider';
26
26
  import * as i6$1 from '@angular/material/select';
27
27
  import { MatSelectModule } from '@angular/material/select';
28
- import { BehaviorSubject, merge, timeout, map, defer, switchMap, concat, of, Observable, from, firstValueFrom, share, concatMap, timer, takeUntil, catchError, filter, take } from 'rxjs';
28
+ import { BehaviorSubject, merge, timeout, map, catchError, throwError, from, firstValueFrom, share, concatMap, of, timer, takeUntil, Subject, filter, take } from 'rxjs';
29
29
  import { SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
30
30
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
31
  import * as i7 from '@angular/material/tabs';
32
32
  import { MatTabsModule } from '@angular/material/tabs';
33
33
  import { HttpClient, HttpHeaders } from '@angular/common/http';
34
- import { AI_STREAM_EVENT_TYPES, toPraxisAssistantConversationMessages, PraxisAssistantTurnOrchestratorService, PraxisAssistantSessionRegistryService, createPraxisAssistantViewportLayout, PraxisAiAssistantShellComponent } from '@praxisui/ai';
34
+ import { AgenticAuthoringTurnClientService, toPraxisAssistantConversationMessages, PraxisAssistantTurnOrchestratorService, PraxisAssistantSessionRegistryService, createPraxisAssistantViewportLayout, PraxisAiAssistantShellComponent } from '@praxisui/ai';
35
35
 
36
36
  const PLACEHOLDER = 1;
37
37
 
@@ -181,6 +181,12 @@ class FloatingToolbarComponent {
181
181
  canRedo = false;
182
182
  showSave = true;
183
183
  showPreview = true;
184
+ editingEnabled = true;
185
+ previewActive = false;
186
+ connectionMode = false;
187
+ modeLabel = '';
188
+ previewLabel = 'Pre-visualizar';
189
+ exitPreviewLabel = 'Voltar para edicao';
184
190
  add = new EventEmitter();
185
191
  undo = new EventEmitter();
186
192
  redo = new EventEmitter();
@@ -188,79 +194,107 @@ class FloatingToolbarComponent {
188
194
  preview = new EventEmitter();
189
195
  save = new EventEmitter();
190
196
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FloatingToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
191
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo", showSave: "showSave", showPreview: "showPreview" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", save: "save" }, ngImport: i0, template: `
197
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo", showSave: "showSave", showPreview: "showPreview", editingEnabled: "editingEnabled", previewActive: "previewActive", connectionMode: "connectionMode", modeLabel: "modeLabel", previewLabel: "previewLabel", exitPreviewLabel: "exitPreviewLabel" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", save: "save" }, ngImport: i0, template: `
192
198
  @if (visible) {
193
- <div class="pdx-floating-toolbar">
199
+ <div
200
+ class="pdx-floating-toolbar"
201
+ [class.pdx-floating-toolbar--connections]="connectionMode"
202
+ [class.pdx-floating-toolbar--preview]="previewActive"
203
+ >
204
+ @if (modeLabel) {
205
+ <span class="pdx-mode-chip" [attr.data-testid]="'page-builder-toolbar-mode'">{{ modeLabel }}</span>
206
+ }
194
207
  <div class="pdx-actions">
195
- <button mat-mini-fab color="primary" (click)="add.emit()" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
208
+ <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
196
209
  <mat-icon [praxisIcon]="'add'"></mat-icon>
197
210
  </button>
198
211
  @if (showSave) {
199
- <button mat-mini-fab color="accent" (click)="save.emit()" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
212
+ <button mat-mini-fab color="accent" (click)="save.emit()" [disabled]="!editingEnabled" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
200
213
  <mat-icon [praxisIcon]="'save'"></mat-icon>
201
214
  </button>
202
215
  }
203
216
  @if (canUndo) {
204
- <button mat-mini-fab (click)="undo.emit()" [matTooltip]="'Desfazer'" aria-label="Desfazer">
217
+ <button mat-mini-fab (click)="undo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Desfazer'" aria-label="Desfazer">
205
218
  <mat-icon [praxisIcon]="'undo'"></mat-icon>
206
219
  </button>
207
220
  }
208
221
  @if (canRedo) {
209
- <button mat-mini-fab (click)="redo.emit()" [matTooltip]="'Refazer'" aria-label="Refazer">
222
+ <button mat-mini-fab (click)="redo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Refazer'" aria-label="Refazer">
210
223
  <mat-icon [praxisIcon]="'redo'"></mat-icon>
211
224
  </button>
212
225
  }
213
- <button mat-mini-fab (click)="settings.emit()" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
226
+ <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
214
227
  <mat-icon [praxisIcon]="'settings'"></mat-icon>
215
228
  </button>
216
229
  @if (showPreview) {
217
- <button mat-mini-fab (click)="preview.emit()" [matTooltip]="'Pre-visualizar'" aria-label="Pre-visualizar">
218
- <mat-icon [praxisIcon]="'visibility'"></mat-icon>
230
+ <button
231
+ mat-mini-fab
232
+ (click)="preview.emit()"
233
+ [class.pdx-preview-toggle--active]="previewActive"
234
+ [matTooltip]="previewActive ? exitPreviewLabel : previewLabel"
235
+ [attr.aria-label]="previewActive ? exitPreviewLabel : previewLabel"
236
+ [attr.aria-pressed]="previewActive"
237
+ >
238
+ <mat-icon [praxisIcon]="previewActive ? 'edit' : 'visibility'"></mat-icon>
219
239
  </button>
220
240
  }
221
241
  <ng-content select="[pdx-toolbar-extra]"></ng-content>
222
242
  </div>
223
243
  </div>
224
244
  }
225
- `, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-actions{display:flex;gap:8px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
245
+ `, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-floating-toolbar--connections{top:16px;bottom:auto}.pdx-mode-chip{display:inline-flex;align-items:center;min-height:28px;max-width:148px;padding:3px 9px;border:1px solid rgba(103,80,164,.22);border-radius:999px;background:#ffffffeb;color:#3f2d75;font-size:11px;font-weight:700;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-shadow:0 8px 22px #0f172a1f}.pdx-actions{display:flex;gap:8px}.pdx-preview-toggle--active{outline:2px solid rgba(103,80,164,.48);outline-offset:2px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}.pdx-floating-toolbar--connections{top:12px;bottom:auto}.pdx-mode-chip{max-width:112px}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
226
246
  }
227
247
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FloatingToolbarComponent, decorators: [{
228
248
  type: Component,
229
249
  args: [{ selector: 'praxis-floating-toolbar', standalone: true, imports: [MatButtonModule, MatIconModule, MatTooltipModule, PraxisIconDirective], template: `
230
250
  @if (visible) {
231
- <div class="pdx-floating-toolbar">
251
+ <div
252
+ class="pdx-floating-toolbar"
253
+ [class.pdx-floating-toolbar--connections]="connectionMode"
254
+ [class.pdx-floating-toolbar--preview]="previewActive"
255
+ >
256
+ @if (modeLabel) {
257
+ <span class="pdx-mode-chip" [attr.data-testid]="'page-builder-toolbar-mode'">{{ modeLabel }}</span>
258
+ }
232
259
  <div class="pdx-actions">
233
- <button mat-mini-fab color="primary" (click)="add.emit()" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
260
+ <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
234
261
  <mat-icon [praxisIcon]="'add'"></mat-icon>
235
262
  </button>
236
263
  @if (showSave) {
237
- <button mat-mini-fab color="accent" (click)="save.emit()" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
264
+ <button mat-mini-fab color="accent" (click)="save.emit()" [disabled]="!editingEnabled" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
238
265
  <mat-icon [praxisIcon]="'save'"></mat-icon>
239
266
  </button>
240
267
  }
241
268
  @if (canUndo) {
242
- <button mat-mini-fab (click)="undo.emit()" [matTooltip]="'Desfazer'" aria-label="Desfazer">
269
+ <button mat-mini-fab (click)="undo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Desfazer'" aria-label="Desfazer">
243
270
  <mat-icon [praxisIcon]="'undo'"></mat-icon>
244
271
  </button>
245
272
  }
246
273
  @if (canRedo) {
247
- <button mat-mini-fab (click)="redo.emit()" [matTooltip]="'Refazer'" aria-label="Refazer">
274
+ <button mat-mini-fab (click)="redo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Refazer'" aria-label="Refazer">
248
275
  <mat-icon [praxisIcon]="'redo'"></mat-icon>
249
276
  </button>
250
277
  }
251
- <button mat-mini-fab (click)="settings.emit()" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
278
+ <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
252
279
  <mat-icon [praxisIcon]="'settings'"></mat-icon>
253
280
  </button>
254
281
  @if (showPreview) {
255
- <button mat-mini-fab (click)="preview.emit()" [matTooltip]="'Pre-visualizar'" aria-label="Pre-visualizar">
256
- <mat-icon [praxisIcon]="'visibility'"></mat-icon>
282
+ <button
283
+ mat-mini-fab
284
+ (click)="preview.emit()"
285
+ [class.pdx-preview-toggle--active]="previewActive"
286
+ [matTooltip]="previewActive ? exitPreviewLabel : previewLabel"
287
+ [attr.aria-label]="previewActive ? exitPreviewLabel : previewLabel"
288
+ [attr.aria-pressed]="previewActive"
289
+ >
290
+ <mat-icon [praxisIcon]="previewActive ? 'edit' : 'visibility'"></mat-icon>
257
291
  </button>
258
292
  }
259
293
  <ng-content select="[pdx-toolbar-extra]"></ng-content>
260
294
  </div>
261
295
  </div>
262
296
  }
263
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-actions{display:flex;gap:8px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"] }]
297
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-floating-toolbar--connections{top:16px;bottom:auto}.pdx-mode-chip{display:inline-flex;align-items:center;min-height:28px;max-width:148px;padding:3px 9px;border:1px solid rgba(103,80,164,.22);border-radius:999px;background:#ffffffeb;color:#3f2d75;font-size:11px;font-weight:700;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-shadow:0 8px 22px #0f172a1f}.pdx-actions{display:flex;gap:8px}.pdx-preview-toggle--active{outline:2px solid rgba(103,80,164,.48);outline-offset:2px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}.pdx-floating-toolbar--connections{top:12px;bottom:auto}.pdx-mode-chip{max-width:112px}}\n"] }]
264
298
  }], propDecorators: { visible: [{
265
299
  type: Input
266
300
  }], canUndo: [{
@@ -271,6 +305,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
271
305
  type: Input
272
306
  }], showPreview: [{
273
307
  type: Input
308
+ }], editingEnabled: [{
309
+ type: Input
310
+ }], previewActive: [{
311
+ type: Input
312
+ }], connectionMode: [{
313
+ type: Input
314
+ }], modeLabel: [{
315
+ type: Input
316
+ }], previewLabel: [{
317
+ type: Input
318
+ }], exitPreviewLabel: [{
319
+ type: Input
274
320
  }], add: [{
275
321
  type: Output
276
322
  }], undo: [{
@@ -337,6 +383,7 @@ class ComponentPaletteDialogComponent {
337
383
  const q = (this.query() || '').toLowerCase();
338
384
  const allowIds = new Set((this.data?.allowedWidgetIds || []).map((s) => s.toLowerCase()));
339
385
  const allowTags = new Set((this.data?.allowedWidgetTags || []).map((s) => s.toLowerCase()));
386
+ const allowPresets = new Set((this.data?.allowedPresetIds || []).map((s) => s.toLowerCase()));
340
387
  const metadataById = new Map(this.registry.getAll().map((meta) => [meta.id, meta]));
341
388
  return list.filter((entry) => {
342
389
  const meta = metadataById.get(entry.componentId);
@@ -349,6 +396,8 @@ class ComponentPaletteDialogComponent {
349
396
  return false;
350
397
  if (allowTags.size > 0 && !meta.tags?.some(t => allowTags.has(t.toLowerCase())))
351
398
  return false;
399
+ if (entry.presetId && allowPresets.size > 0 && !allowPresets.has(entry.presetId.toLowerCase()))
400
+ return false;
352
401
  if (typeof this.data?.predicate === 'function' && !this.data.predicate(meta))
353
402
  return false;
354
403
  return true;
@@ -2390,8 +2439,22 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2390
2439
  'praxis.pageBuilder.editor.hints.schemaInitial': 'Define the initial value of this state path. This helps the page start in a consistent state even before remote connections and data.',
2391
2440
  'praxis.pageBuilder.editor.hints.templateJson': 'JSON templates are useful to generate complete derived objects, such as texts, summary cards or shell settings.',
2392
2441
  'praxis.pageBuilder.editor.hints.transformerOptions': 'Pass the registered transformer options here. Prefer lean JSON with only the parameters actually used by the runtime.',
2442
+ 'praxis.pageBuilder.toolbar.preview': 'Preview',
2443
+ 'praxis.pageBuilder.toolbar.exitPreview': 'Back to editing',
2444
+ 'praxis.pageBuilder.builderMode.editing': 'Editing',
2445
+ 'praxis.pageBuilder.builderMode.connections': 'Connections',
2446
+ 'praxis.pageBuilder.builderMode.ai': 'AI',
2447
+ 'praxis.pageBuilder.builderMode.preview': 'Preview',
2448
+ 'praxis.pageBuilder.builderMode.presentation': 'Presentation',
2449
+ 'praxis.pageBuilder.premiumReadiness.actions.openPageSettings': 'Open page settings',
2450
+ 'praxis.pageBuilder.premiumReadiness.actions.reviewTheme': 'Review theme',
2451
+ 'praxis.pageBuilder.premiumReadiness.actions.openDeviceLayouts': 'Open layouts',
2452
+ 'praxis.pageBuilder.premiumReadiness.actions.openConnections': 'Open connections',
2453
+ 'praxis.pageBuilder.premiumReadiness.actions.openWidgetConfig': 'Open widget',
2454
+ 'praxis.pageBuilder.premiumReadiness.actions.focusChart': 'Focus chart',
2393
2455
  'praxis.pageBuilder.connections.toggle': 'Edit connections',
2394
2456
  'praxis.pageBuilder.connections.toggleAria': 'Edit connections',
2457
+ 'praxis.pageBuilder.connections.close': 'Close connections',
2395
2458
  'praxis.pageBuilder.connections.title': 'Connections',
2396
2459
  'praxis.pageBuilder.connections.editor.panelAria': 'Connection editor',
2397
2460
  'praxis.pageBuilder.connections.editor.eyebrow': 'Radial connection studio',
@@ -2549,12 +2612,12 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2549
2612
  'praxis.pageBuilder.agentic.header.title.widget': 'Praxis widget copilot',
2550
2613
  'praxis.pageBuilder.agentic.header.title.review': 'Praxis review copilot',
2551
2614
  'praxis.pageBuilder.agentic.header.title.governed': 'Praxis governed copilot',
2552
- 'praxis.pageBuilder.agentic.header.subtitle.page': 'Turn intent into layout, widgets, and governed materializations.',
2553
- 'praxis.pageBuilder.agentic.header.subtitle.route': 'Authoring page route {route}.',
2615
+ 'praxis.pageBuilder.agentic.header.subtitle.page': 'Turn a domain need into a table, form, or dashboard.',
2616
+ 'praxis.pageBuilder.agentic.header.subtitle.route': 'Creating or adjusting page {route}.',
2554
2617
  'praxis.pageBuilder.agentic.header.subtitle.widget': 'Focused on {target}.',
2555
- 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Preview ready for governed review.',
2556
- 'praxis.pageBuilder.agentic.header.subtitle.review': 'Preview ready for review and persistence.',
2557
- 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue the governed semantic-decision flow.',
2618
+ 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Preview ready, with points to review.',
2619
+ 'praxis.pageBuilder.agentic.header.subtitle.review': 'Preview ready to review and save.',
2620
+ 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue the rule review before creating the screen.',
2558
2621
  'praxis.pageBuilder.agentic.header.mode.page': 'Page',
2559
2622
  'praxis.pageBuilder.agentic.header.mode.widget': 'Widget',
2560
2623
  'praxis.pageBuilder.agentic.header.mode.governed': 'Governed',
@@ -2570,13 +2633,13 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2570
2633
  'praxis.pageBuilder.agentic.dock.badgeGoverned': 'Governed',
2571
2634
  'praxis.pageBuilder.agentic.dock.badgeReady': 'Ready',
2572
2635
  'praxis.pageBuilder.agentic.dock.summaryReview': 'Preview ready. Reopen to review or save.',
2573
- 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Governed handoff preserved. Continue the semantic decision flow.',
2636
+ 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Review preserved. Continue where you left off.',
2574
2637
  'praxis.pageBuilder.agentic.dock.summaryIdle': 'Conversation preserved. Continue where you stopped.',
2575
2638
  'praxis.pageBuilder.agentic.promptLabel': 'Message',
2576
2639
  'praxis.pageBuilder.agentic.promptPlaceholder': 'Describe the page, dashboard, form, or change you need.',
2577
2640
  'praxis.pageBuilder.agentic.emptyConversation': 'Describe the outcome you want. I will ground the context, prepare a governed preview, and wait for review before applying anything.',
2578
- 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'This host page is still blank. Tell me what decision or activity this app needs to support. I can suggest a dashboard, table, form, or review flow, then turn it into a governed preview for you to review before anything changes.',
2579
- 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Tell me what you want to improve here. I can read the current layout, widgets, route, and governed context, then prepare a preview for you to review before anything changes.',
2641
+ 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'This screen is still empty. Tell me which domain activity it should support. I can suggest a dashboard, table, or form and prepare a preview for you to review before saving.',
2642
+ 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Tell me what you want to improve on this screen. I will read what already exists and prepare a preview for you to review before saving.',
2580
2643
  'praxis.pageBuilder.agentic.conversationAria': 'AI conversation',
2581
2644
  'praxis.pageBuilder.agentic.quickRepliesAria': 'Quick replies',
2582
2645
  'praxis.pageBuilder.agentic.contextAria': 'Active context',
@@ -2666,6 +2729,7 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2666
2729
  'praxis.pageBuilder.agentic.dragHandleAria': 'Move AI assistant',
2667
2730
  'praxis.pageBuilder.agentic.resizeHandleAria': 'Resize AI assistant',
2668
2731
  'praxis.pageBuilder.agentic.resizeHandleTooltip': 'Resize',
2732
+ 'praxis.pageBuilder.agentic.submit': 'Send request',
2669
2733
  'praxis.pageBuilder.agentic.preview': 'Generate preview',
2670
2734
  'praxis.pageBuilder.agentic.persist': 'Save',
2671
2735
  'praxis.pageBuilder.pageLifecycle.restart': 'Restart page',
@@ -2692,8 +2756,39 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2692
2756
  'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Field label updated.',
2693
2757
  'praxis.pageBuilder.agentic.status.saving': 'Saving page...',
2694
2758
  'praxis.pageBuilder.agentic.status.saved': 'Page saved.',
2695
- 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Shared-rule target selected. Continue by creating the governed definition.',
2696
- 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Shared-rule target selected. The next safe step is creating the governed definition.',
2759
+ 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Continue this request in the rule review.',
2760
+ 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'This request needs to continue through governed business-rule review. I will not create a local preview while that review is unavailable.',
2761
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.title': 'Governed rule review',
2762
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.description': 'Review the business rule before creating or saving screen changes.',
2763
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.expand': 'Expand',
2764
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.collapse': 'Collapse',
2765
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Rule identified. The next safe step is reviewing the rule before creating the screen.',
2766
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.running': 'Running review step',
2767
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.definitionId': 'Rule',
2768
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.simulation': 'Simulation',
2769
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.publication': 'Publication',
2770
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.materializations': 'Created screens',
2771
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.timeline': 'History',
2772
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementState': 'Validation',
2773
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrix': 'Change validation',
2774
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrixDescription': 'Changes the platform can apply after publication.',
2775
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.pending': 'pending',
2776
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.applied': 'applied',
2777
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.waiting': 'waiting',
2778
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.label': 'Review rule',
2779
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.description': 'Open or create the governed rule review.',
2780
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.label': 'Simulate',
2781
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.description': 'Test the result before publishing.',
2782
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.label': 'Approve',
2783
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.description': 'Approve the rule after review.',
2784
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.label': 'Publish changes',
2785
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.description': 'Publish the rule and prepare derived screens.',
2786
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.label': 'View created screens',
2787
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.description': 'View the screens generated from the approved rule.',
2788
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.label': 'Validate application',
2789
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.description': 'Check whether published changes are ready to use.',
2790
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.label': 'View history',
2791
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.description': 'Open the safe history for this decision.',
2697
2792
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timeline': 'Safe timeline',
2698
2793
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timelineEmpty': 'No safe timeline events published for this change-set yet.',
2699
2794
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.rejected': 'Project Knowledge change-set rejected. No governed knowledge projection was applied.',
@@ -2704,7 +2799,6 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2704
2799
  'praxis.pageBuilder.agentic.errors.streamTimeout': 'The assistant took too long to finish this request. Try again with a narrower request or review the active context.',
2705
2800
  'praxis.pageBuilder.agentic.errors.streamProcessing': 'The assistant could not finish this authoring request. Try again or ask support to review the diagnostics.',
2706
2801
  'praxis.pageBuilder.agentic.errors.streamConnection': 'The assistant stream was interrupted before the turn finished. Try again or ask support to check the stream connection.',
2707
- 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'This request must continue through the governed semantic-decision flow in /api/praxis/config/domain-rules. The backend stream is unavailable, so local preview/apply is blocked.',
2708
2802
  'praxis.pageBuilder.agentic.errors.duplicateField': 'This field already exists in the selected form.',
2709
2803
  'praxis.pageBuilder.agentic.errors.nonLocalFieldRemoval': 'Only local fields created by AI can be removed in this flow.',
2710
2804
  'praxis.pageBuilder.agentic.errors.invalidTableContract': 'I found the data source, but the generated plan used properties that are incompatible with the table component. I will adjust it to use only supported fields.',
@@ -2834,8 +2928,22 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2834
2928
  'praxis.pageBuilder.editor.hints.schemaInitial': 'Defina o valor inicial desse caminho de estado. Isso ajuda a página a nascer em um estado consistente mesmo antes de conexões e dados remotos.',
2835
2929
  'praxis.pageBuilder.editor.hints.templateJson': 'Modelos em JSON são úteis para gerar objetos derivados completos, como textos, cartões de resumo ou configurações de shell.',
2836
2930
  'praxis.pageBuilder.editor.hints.transformerOptions': 'Passe aqui as opções do transformador registrado. Prefira JSON enxuto com os parâmetros realmente usados pelo runtime.',
2931
+ 'praxis.pageBuilder.toolbar.preview': 'Pré-visualizar',
2932
+ 'praxis.pageBuilder.toolbar.exitPreview': 'Voltar para edição',
2933
+ 'praxis.pageBuilder.builderMode.editing': 'Edição',
2934
+ 'praxis.pageBuilder.builderMode.connections': 'Conexões',
2935
+ 'praxis.pageBuilder.builderMode.ai': 'IA',
2936
+ 'praxis.pageBuilder.builderMode.preview': 'Prévia',
2937
+ 'praxis.pageBuilder.builderMode.presentation': 'Apresentação',
2938
+ 'praxis.pageBuilder.premiumReadiness.actions.openPageSettings': 'Abrir configurações da página',
2939
+ 'praxis.pageBuilder.premiumReadiness.actions.reviewTheme': 'Revisar tema',
2940
+ 'praxis.pageBuilder.premiumReadiness.actions.openDeviceLayouts': 'Abrir layouts',
2941
+ 'praxis.pageBuilder.premiumReadiness.actions.openConnections': 'Abrir conexões',
2942
+ 'praxis.pageBuilder.premiumReadiness.actions.openWidgetConfig': 'Abrir widget',
2943
+ 'praxis.pageBuilder.premiumReadiness.actions.focusChart': 'Focar gráfico',
2837
2944
  'praxis.pageBuilder.connections.toggle': 'Editar conexões',
2838
2945
  'praxis.pageBuilder.connections.toggleAria': 'Editar conexões',
2946
+ 'praxis.pageBuilder.connections.close': 'Fechar conexões',
2839
2947
  'praxis.pageBuilder.connections.title': 'Conexões',
2840
2948
  'praxis.pageBuilder.connections.editor.panelAria': 'Editor de conexões',
2841
2949
  'praxis.pageBuilder.connections.editor.eyebrow': 'Estúdio radial de conexões',
@@ -2993,12 +3101,12 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2993
3101
  'praxis.pageBuilder.agentic.header.title.widget': 'Copiloto de componente Praxis',
2994
3102
  'praxis.pageBuilder.agentic.header.title.review': 'Copiloto de revisão Praxis',
2995
3103
  'praxis.pageBuilder.agentic.header.title.governed': 'Copiloto governado Praxis',
2996
- 'praxis.pageBuilder.agentic.header.subtitle.page': 'Transforme intenção em layout, widgets e materializações governadas.',
2997
- 'praxis.pageBuilder.agentic.header.subtitle.route': 'Autoria da rota {route}.',
3104
+ 'praxis.pageBuilder.agentic.header.subtitle.page': 'Transforme uma necessidade do domínio em tabela, formulário ou painel.',
3105
+ 'praxis.pageBuilder.agentic.header.subtitle.route': 'Criando ou ajustando a página {route}.',
2998
3106
  'praxis.pageBuilder.agentic.header.subtitle.widget': 'Foco em {target}.',
2999
- 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Prévia pronta para revisão governada.',
3000
- 'praxis.pageBuilder.agentic.header.subtitle.review': 'Prévia pronta para revisão e persistência.',
3001
- 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue o fluxo governado de decisão semântica.',
3107
+ 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Prévia pronta, com pontos para revisar.',
3108
+ 'praxis.pageBuilder.agentic.header.subtitle.review': 'Prévia pronta para revisar e salvar.',
3109
+ 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue a revisão da regra antes de criar a tela.',
3002
3110
  'praxis.pageBuilder.agentic.header.mode.page': 'Página',
3003
3111
  'praxis.pageBuilder.agentic.header.mode.widget': 'Widget',
3004
3112
  'praxis.pageBuilder.agentic.header.mode.governed': 'Governado',
@@ -3014,13 +3122,13 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3014
3122
  'praxis.pageBuilder.agentic.dock.badgeGoverned': 'Governado',
3015
3123
  'praxis.pageBuilder.agentic.dock.badgeReady': 'Pronto',
3016
3124
  'praxis.pageBuilder.agentic.dock.summaryReview': 'Prévia pronta. Reabra para revisar ou salvar.',
3017
- 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Handoff governado preservado. Continue o fluxo de decisão semântica.',
3125
+ 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Revisão preservada. Continue de onde parou.',
3018
3126
  'praxis.pageBuilder.agentic.dock.summaryIdle': 'Conversa preservada. Continue de onde parou.',
3019
3127
  'praxis.pageBuilder.agentic.promptLabel': 'Mensagem',
3020
3128
  'praxis.pageBuilder.agentic.promptPlaceholder': 'Descreva a página, dashboard, formulário ou alteração que você precisa.',
3021
3129
  'praxis.pageBuilder.agentic.emptyConversation': 'Descreva o resultado que você quer. Vou fundamentar o contexto, preparar uma prévia governada e aguardar revisão antes de aplicar qualquer mudança.',
3022
- 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'Esta página do host ainda está em branco. Conte qual decisão ou atividade este app precisa apoiar. Posso sugerir um dashboard, tabela, formulário ou fluxo de revisão e transformar isso em uma prévia governada para você revisar antes de qualquer mudança.',
3023
- 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Conte o que você quer melhorar aqui. Posso ler o layout atual, widgets, rota e contexto governado, depois preparar uma prévia para você revisar antes de qualquer mudança.',
3130
+ 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'Esta tela ainda está vazia. Diga qual atividade do domínio ela precisa apoiar. Posso sugerir um painel, tabela ou formulário e montar uma prévia para você revisar antes de salvar.',
3131
+ 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Diga o que você quer melhorar nesta tela. Eu leio o que existe e preparo uma prévia para você revisar antes de salvar.',
3024
3132
  'praxis.pageBuilder.agentic.conversationAria': 'Conversa com IA',
3025
3133
  'praxis.pageBuilder.agentic.quickRepliesAria': 'Respostas rápidas',
3026
3134
  'praxis.pageBuilder.agentic.contextAria': 'Contexto ativo',
@@ -3101,7 +3209,7 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3101
3209
  'praxis.pageBuilder.agentic.resourceDiscovery.useResource': 'Usar {resourcePath}',
3102
3210
  'praxis.pageBuilder.agentic.resourceDiscovery.defaultRecommendedLabel': 'a primeira opção',
3103
3211
  'praxis.pageBuilder.agentic.resourceDiscovery.cardDescription': 'Fonte recomendada para transformar {label} em painel: ajuda a escolher gráficos, listas, filtros e formatos antes de materializar a tela.',
3104
- 'praxis.pageBuilder.agentic.resourceDiscovery.cardBestFor': 'Quando você quer entender se {label} responde ao objetivo de negócio antes de criar widgets.',
3212
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardBestFor': 'Quando você precisa decidir se {label} é a melhor fonte para a experiência que está criando.',
3105
3213
  'praxis.pageBuilder.agentic.resourceDiscovery.cardReturns': 'Sugere métricas, dimensões, filtros, formatos de valor, gráficos e listas de detalhe compatíveis com a fonte.',
3106
3214
  'praxis.pageBuilder.agentic.resourceDiscovery.cardNextStep': 'Selecione para eu propor uma pré-visualização governada com cards ricos, drill-down e formatos adequados por padrão.',
3107
3215
  'praxis.pageBuilder.agentic.diagnostics.title': 'Diagnóstico do LLM',
@@ -3110,6 +3218,7 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3110
3218
  'praxis.pageBuilder.agentic.dragHandleAria': 'Mover assistente de IA',
3111
3219
  'praxis.pageBuilder.agentic.resizeHandleAria': 'Redimensionar assistente de IA',
3112
3220
  'praxis.pageBuilder.agentic.resizeHandleTooltip': 'Redimensionar',
3221
+ 'praxis.pageBuilder.agentic.submit': 'Enviar pedido',
3113
3222
  'praxis.pageBuilder.agentic.preview': 'Gerar prévia',
3114
3223
  'praxis.pageBuilder.agentic.persist': 'Salvar',
3115
3224
  'praxis.pageBuilder.pageLifecycle.restart': 'Recomeçar tela',
@@ -3136,8 +3245,39 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3136
3245
  'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Rótulo do campo atualizado.',
3137
3246
  'praxis.pageBuilder.agentic.status.saving': 'Salvando página...',
3138
3247
  'praxis.pageBuilder.agentic.status.saved': 'Página salva.',
3139
- 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Alvo de regra compartilhada selecionado. Continue criando a definição governada.',
3140
- 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Alvo de regra compartilhada selecionado. O próximo passo seguro é criar a definição governada.',
3248
+ 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Continue este pedido na revisão da regra.',
3249
+ 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'Este pedido precisa continuar pela revisão governada da regra de negócio. Não vou criar uma prévia local enquanto essa revisão não estiver disponível.',
3250
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.title': 'Revisão governada da regra',
3251
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.description': 'Revise a regra de negócio antes de criar ou salvar alterações na tela.',
3252
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.expand': 'Expandir',
3253
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.collapse': 'Recolher',
3254
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Regra identificada. O próximo passo seguro é revisar a regra antes de criar a tela.',
3255
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.running': 'Executando etapa de revisão',
3256
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.definitionId': 'Regra',
3257
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.simulation': 'Simulação',
3258
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.publication': 'Publicação',
3259
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.materializations': 'Telas criadas',
3260
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.timeline': 'Histórico',
3261
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementState': 'Validação',
3262
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrix': 'Validação das alterações',
3263
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrixDescription': 'Alterações que a plataforma poderá aplicar depois da publicação.',
3264
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.pending': 'pendente',
3265
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.applied': 'aplicadas',
3266
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.waiting': 'aguardando',
3267
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.label': 'Revisar regra',
3268
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.description': 'Abrir ou criar a revisão governada da regra.',
3269
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.label': 'Simular',
3270
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.description': 'Testar o resultado antes de publicar.',
3271
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.label': 'Aprovar',
3272
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.description': 'Aprovar a regra depois da revisão.',
3273
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.label': 'Publicar alterações',
3274
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.description': 'Publicar a regra e preparar as telas derivadas.',
3275
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.label': 'Ver telas criadas',
3276
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.description': 'Ver as telas geradas a partir da regra aprovada.',
3277
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.label': 'Validar aplicação',
3278
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.description': 'Verificar se as alterações publicadas já podem ser usadas.',
3279
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.label': 'Ver histórico',
3280
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.description': 'Abrir o histórico seguro desta decisão.',
3141
3281
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timeline': 'Timeline segura',
3142
3282
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timelineEmpty': 'Ainda não há eventos seguros de timeline publicados para este change-set.',
3143
3283
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.rejected': 'Change-set de Project Knowledge rejeitado. Nenhuma projeção de conhecimento governado foi aplicada.',
@@ -3148,7 +3288,6 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3148
3288
  'praxis.pageBuilder.agentic.errors.streamTimeout': 'Ainda não consegui concluir este pedido. Tente novamente com um pedido mais específico ou revise o contexto ativo.',
3149
3289
  'praxis.pageBuilder.agentic.errors.streamProcessing': 'Não consegui concluir este pedido de autoria. Tente novamente ou peça ao suporte para revisar o diagnóstico.',
3150
3290
  'praxis.pageBuilder.agentic.errors.streamConnection': 'O stream do assistente foi interrompido antes de concluir o turno. Tente novamente ou acione o suporte para verificar a conexão do stream.',
3151
- 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'Este pedido deve continuar pelo fluxo governado de decisão semântica em /api/praxis/config/domain-rules. O stream do backend está indisponível, então pré-visualização/aplicação local fica bloqueada.',
3152
3291
  'praxis.pageBuilder.agentic.errors.duplicateField': 'Este campo já existe no formulário selecionado.',
3153
3292
  'praxis.pageBuilder.agentic.errors.nonLocalFieldRemoval': 'Somente campos locais criados pela IA podem ser removidos neste fluxo.',
3154
3293
  'praxis.pageBuilder.agentic.errors.invalidTableContract': 'Encontrei a fonte de dados, mas o plano gerado usou propriedades incompatíveis com o componente de tabela. Vou ajustar para usar apenas os campos suportados.',
@@ -12055,11 +12194,12 @@ const PAGE_BUILDER_COMPONENT_CONTEXT_PACK = {
12055
12194
  const DEFAULT_AGENTIC_AUTHORING_REQUEST_TIMEOUT_MS = 120000;
12056
12195
  const DEFAULT_TURN_STREAM_START_TIMEOUT_MS = 10000;
12057
12196
  const DEFAULT_TURN_STREAM_TIMEOUT_MS = 240000;
12058
- const DEFAULT_TURN_STREAM_RESULT_FALLBACK_MS = 90000;
12197
+ const DEFAULT_TURN_STREAM_RESULT_FALLBACK_MS = 210000;
12059
12198
  const DEFAULT_TURN_STREAM_SILENCE_STATUS_MS = 20000;
12060
12199
  const PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS = new InjectionToken('PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS');
12061
12200
  class PageBuilderAgenticAuthoringService {
12062
12201
  http = inject(HttpClient);
12202
+ turnClient = inject(AgenticAuthoringTurnClientService);
12063
12203
  options = inject(PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, {
12064
12204
  optional: true,
12065
12205
  });
@@ -12078,15 +12218,14 @@ class PageBuilderAgenticAuthoringService {
12078
12218
  return this.http.post(`${this.baseUrl}/resource-candidates`, request, { headers: this.buildHeaders() }).pipe(timeout({ first: this.requestTimeoutMs() }));
12079
12219
  }
12080
12220
  streamTurn(request) {
12081
- return defer(() => {
12082
- const startRequestedAt = Date.now();
12083
- return this.http.post(`${this.baseUrl}/turn/stream/start`, request, { headers: this.buildHeaders(), withCredentials: true }).pipe(timeout({ first: this.streamStartTimeoutMs() }), map((start) => ({
12084
- start,
12085
- startRequestElapsedMs: Math.max(0, Date.now() - startRequestedAt),
12086
- })));
12087
- }).pipe(switchMap(({ start, startRequestElapsedMs }) => concat(of(this.streamLifecycleStatusEvent(start, 'stream.start.accepted', {
12088
- startRequestElapsedMs,
12089
- })), this.connectTurnStream(start, { startRequestElapsedMs }))));
12221
+ const startRequestedAt = Date.now();
12222
+ return this.turnClient.streamEvents(request, {
12223
+ baseUrl: this.baseUrl,
12224
+ headers: this.buildHeaderRecord(),
12225
+ silenceStatusMs: this.streamSilenceStatusMs(),
12226
+ resultTimeoutMs: this.streamResultFallbackMs(),
12227
+ streamTimeoutMs: this.streamTurnTimeoutMs(),
12228
+ }).pipe(timeout({ first: this.streamStartTimeoutMs() }), map((event) => this.toTurnStreamEvent(event, startRequestedAt)), catchError((error) => throwError(() => this.toTurnStreamError(error))));
12090
12229
  }
12091
12230
  applyPage(request) {
12092
12231
  const { ifMatch, ...body } = request;
@@ -12101,7 +12240,7 @@ class PageBuilderAgenticAuthoringService {
12101
12240
  headers: this.buildHeaders(ifMatch ? { 'If-Match': this.formatEtag(ifMatch) } : undefined),
12102
12241
  });
12103
12242
  }
12104
- buildHeaders(extra) {
12243
+ buildHeaderRecord(extra) {
12105
12244
  const merged = {
12106
12245
  ...(this.options?.defaultHeaders ?? {}),
12107
12246
  };
@@ -12116,271 +12255,50 @@ class PageBuilderAgenticAuthoringService {
12116
12255
  merged[key] = value;
12117
12256
  }
12118
12257
  }
12119
- return new HttpHeaders(merged);
12120
- }
12121
- connectTurnStream(start, telemetry) {
12122
- return new Observable((observer) => {
12123
- const connectStartedAt = Date.now();
12124
- const url = this.buildStreamUrl(start);
12125
- const probeUrl = this.buildStreamProbeUrl(start);
12126
- let source = null;
12127
- let closed = false;
12128
- let firstEventReceived = false;
12129
- let streamTimeout = null;
12130
- let resultFallbackTimeout = null;
12131
- let silenceStatusTimeout = null;
12132
- const streamTimeoutMs = this.streamTurnTimeoutMs();
12133
- const resultFallbackMs = this.streamResultFallbackMs();
12134
- const silenceStatusMs = this.streamSilenceStatusMs();
12135
- let probeAbort = typeof AbortController !== 'undefined'
12136
- ? new AbortController()
12137
- : null;
12138
- let streamAbort = null;
12139
- const clearStreamTimeout = () => {
12140
- if (streamTimeout) {
12141
- clearTimeout(streamTimeout);
12142
- streamTimeout = null;
12143
- }
12144
- };
12145
- const clearResultFallbackTimeout = () => {
12146
- if (resultFallbackTimeout) {
12147
- clearTimeout(resultFallbackTimeout);
12148
- resultFallbackTimeout = null;
12149
- }
12150
- };
12151
- const clearSilenceStatusTimeout = () => {
12152
- if (silenceStatusTimeout) {
12153
- clearTimeout(silenceStatusTimeout);
12154
- silenceStatusTimeout = null;
12155
- }
12156
- };
12157
- const closeSource = () => {
12158
- if (closed) {
12159
- return;
12160
- }
12161
- closed = true;
12162
- clearStreamTimeout();
12163
- clearResultFallbackTimeout();
12164
- clearSilenceStatusTimeout();
12165
- streamAbort?.abort();
12166
- streamAbort = null;
12167
- source?.close();
12168
- };
12169
- const startSilenceStatusTimer = () => {
12170
- clearSilenceStatusTimeout();
12171
- if (silenceStatusMs <= 0)
12172
- return;
12173
- silenceStatusTimeout = setTimeout(() => {
12174
- if (closed)
12175
- return;
12176
- observer.next(this.streamSilenceStatusEvent(start, silenceStatusMs, resultFallbackMs));
12177
- }, silenceStatusMs);
12178
- };
12179
- const startResultFallbackTimer = () => {
12180
- clearResultFallbackTimeout();
12181
- if (resultFallbackMs <= 0)
12182
- return;
12183
- resultFallbackTimeout = setTimeout(() => {
12184
- if (closed)
12185
- return;
12186
- streamAbort?.abort();
12187
- streamAbort = null;
12188
- source?.close();
12189
- observer.error(this.streamConnectionError({
12190
- code: 'agentic-authoring-result-fallback',
12191
- message: `Agentic authoring stream did not deliver a result after ${resultFallbackMs}ms.`,
12192
- fallbackAuthoringUrl: start.fallbackAuthoringUrl ?? null,
12193
- }));
12194
- closeSource();
12195
- }, resultFallbackMs);
12196
- };
12197
- streamTimeout = setTimeout(() => {
12198
- if (closed) {
12199
- return;
12200
- }
12201
- observer.error({
12202
- name: 'TimeoutError',
12203
- code: 'agentic-authoring-timeout',
12204
- message: `Agentic authoring turn timed out after ${streamTimeoutMs}ms.`,
12205
- });
12206
- closeSource();
12207
- }, streamTimeoutMs);
12208
- const handleMessage = (event) => {
12209
- let parsed;
12210
- try {
12211
- parsed = JSON.parse(event.data);
12212
- }
12213
- catch (error) {
12214
- observer.error(this.streamConnectionError(error));
12215
- closeSource();
12216
- return;
12217
- }
12218
- if (!firstEventReceived) {
12219
- firstEventReceived = true;
12220
- observer.next(this.streamLifecycleStatusEvent(start, 'stream.first-event.received', {
12221
- startRequestElapsedMs: telemetry.startRequestElapsedMs,
12222
- connectElapsedMs: Math.max(0, Date.now() - connectStartedAt),
12223
- firstEventSeq: parsed.seq ?? null,
12224
- firstEventType: parsed.type ?? null,
12225
- }));
12226
- }
12227
- clearSilenceStatusTimeout();
12228
- observer.next(parsed);
12229
- if (parsed.type === 'result' || parsed.type === 'error' || parsed.type === 'cancelled') {
12230
- clearResultFallbackTimeout();
12231
- observer.complete();
12232
- closeSource();
12233
- }
12234
- };
12235
- void this.probeTurnStreamEndpoint(probeUrl, probeAbort)
12236
- .then((status) => {
12237
- probeAbort = null;
12238
- if (closed) {
12239
- return;
12240
- }
12241
- if (typeof status === 'number' && status >= 400) {
12242
- closed = true;
12243
- observer.error(this.streamConnectionError({ status }));
12244
- return;
12245
- }
12246
- observer.next(this.streamLifecycleStatusEvent(start, 'stream.probe.ready', {
12247
- startRequestElapsedMs: telemetry.startRequestElapsedMs,
12248
- connectElapsedMs: Math.max(0, Date.now() - connectStartedAt),
12249
- probeStatus: status,
12250
- }));
12251
- if (!this.options?.eventSourceFactory && typeof fetch === 'function' && typeof TextDecoder !== 'undefined') {
12252
- streamAbort = typeof AbortController !== 'undefined' ? new AbortController() : null;
12253
- observer.next(this.streamLifecycleStatusEvent(start, 'stream.transport.opening', {
12254
- startRequestElapsedMs: telemetry.startRequestElapsedMs,
12255
- connectElapsedMs: Math.max(0, Date.now() - connectStartedAt),
12256
- transport: 'fetch',
12257
- }));
12258
- startResultFallbackTimer();
12259
- startSilenceStatusTimer();
12260
- void this.consumeFetchTurnStream(url, streamAbort, handleMessage, () => closed).catch((error) => {
12261
- if (closed) {
12262
- return;
12263
- }
12264
- observer.error(this.streamConnectionError(error));
12265
- closeSource();
12266
- });
12267
- return;
12268
- }
12269
- try {
12270
- source = this.createEventSource(url);
12271
- }
12272
- catch (error) {
12273
- closed = true;
12274
- observer.error(this.streamConnectionError(error));
12275
- return;
12276
- }
12277
- observer.next(this.streamLifecycleStatusEvent(start, 'stream.transport.opening', {
12278
- startRequestElapsedMs: telemetry.startRequestElapsedMs,
12279
- connectElapsedMs: Math.max(0, Date.now() - connectStartedAt),
12280
- transport: 'event-source',
12281
- }));
12282
- startResultFallbackTimer();
12283
- startSilenceStatusTimer();
12284
- source.onmessage = handleMessage;
12285
- if (source.addEventListener) {
12286
- for (const type of AI_STREAM_EVENT_TYPES) {
12287
- source.addEventListener(type, handleMessage);
12288
- }
12289
- }
12290
- source.onerror = (event) => {
12291
- if (closed) {
12292
- return;
12293
- }
12294
- if (source?.readyState === EventSource.CLOSED) {
12295
- observer.error(this.streamConnectionError(event));
12296
- closeSource();
12297
- }
12298
- };
12299
- })
12300
- .catch((error) => {
12301
- if (closed) {
12302
- return;
12303
- }
12304
- closed = true;
12305
- clearStreamTimeout();
12306
- observer.error(this.streamConnectionError(error));
12307
- });
12308
- return () => {
12309
- probeAbort?.abort();
12310
- if (source) {
12311
- closeSource();
12312
- return;
12313
- }
12314
- closed = true;
12315
- streamAbort?.abort();
12316
- streamAbort = null;
12317
- clearStreamTimeout();
12318
- clearResultFallbackTimeout();
12319
- clearSilenceStatusTimeout();
12320
- };
12321
- });
12258
+ return merged;
12322
12259
  }
12323
- async consumeFetchTurnStream(url, abort, handleMessage, closed) {
12324
- const response = await fetch(url, {
12325
- method: 'GET',
12326
- headers: { Accept: 'text/event-stream' },
12327
- credentials: 'include',
12328
- cache: 'no-store',
12329
- signal: abort?.signal,
12330
- });
12331
- if (!response.ok) {
12332
- throw { status: response.status };
12260
+ buildHeaders(extra) {
12261
+ return new HttpHeaders(this.buildHeaderRecord(extra));
12262
+ }
12263
+ toTurnStreamEvent(event, startRequestedAt) {
12264
+ if (event.kind === 'stream-started') {
12265
+ return this.streamLifecycleStatusEvent(event.start, 'stream.start.accepted', {
12266
+ startRequestElapsedMs: Math.max(0, Date.now() - startRequestedAt),
12267
+ });
12333
12268
  }
12334
- if (!response.body) {
12335
- throw new Error('Agentic authoring stream response does not expose a readable body.');
12269
+ if (event.kind === 'stream-lifecycle') {
12270
+ return this.streamLifecycleStatusEvent(event.start, event.phase, {
12271
+ startRequestElapsedMs: Math.max(0, Date.now() - startRequestedAt),
12272
+ ...(event.diagnostics ?? {}),
12273
+ });
12336
12274
  }
12337
- const reader = response.body.getReader();
12338
- const decoder = new TextDecoder();
12339
- let buffer = '';
12340
- try {
12341
- while (!closed()) {
12342
- const { value, done } = await reader.read();
12343
- if (done) {
12344
- break;
12345
- }
12346
- buffer += decoder.decode(value, { stream: true });
12347
- buffer = this.consumeBufferedSseFrames(buffer, handleMessage);
12348
- }
12349
- buffer += decoder.decode();
12350
- this.consumeBufferedSseFrames(`${buffer}\n\n`, handleMessage);
12275
+ return event.event;
12276
+ }
12277
+ toTurnStreamError(error) {
12278
+ const record = this.toRecord(error);
12279
+ if (record && record['code'] === 'agentic-authoring-timeout') {
12280
+ return error;
12281
+ }
12282
+ if (record && record['code'] === 'agentic-authoring-result-timeout') {
12283
+ return this.streamConnectionError({
12284
+ code: 'agentic-authoring-result-fallback',
12285
+ message: typeof record['message'] === 'string'
12286
+ ? record['message']
12287
+ : 'Agentic authoring stream did not deliver a result.',
12288
+ fallbackAuthoringUrl: typeof record['fallbackAuthoringUrl'] === 'string'
12289
+ ? record['fallbackAuthoringUrl']
12290
+ : null,
12291
+ });
12351
12292
  }
12352
- finally {
12353
- reader.releaseLock();
12354
- }
12355
- }
12356
- consumeBufferedSseFrames(buffer, handleMessage) {
12357
- let remaining = buffer;
12358
- let boundary = this.findSseFrameBoundary(remaining);
12359
- while (boundary) {
12360
- const frame = remaining.slice(0, boundary.index);
12361
- remaining = remaining.slice(boundary.index + boundary.length);
12362
- const data = frame
12363
- .split(/\r?\n/)
12364
- .filter((line) => line.startsWith('data:'))
12365
- .map((line) => line.slice(5).trimStart())
12366
- .join('\n');
12367
- if (data) {
12368
- handleMessage({ data });
12369
- }
12370
- boundary = this.findSseFrameBoundary(remaining);
12293
+ if (record && record['praxisAgenticTurnStreamConnectionError'] === true) {
12294
+ return error;
12371
12295
  }
12372
- return remaining;
12296
+ return this.streamConnectionError(error);
12373
12297
  }
12374
- findSseFrameBoundary(buffer) {
12375
- const lf = buffer.indexOf('\n\n');
12376
- const crlf = buffer.indexOf('\r\n\r\n');
12377
- if (lf < 0 && crlf < 0) {
12378
- return null;
12379
- }
12380
- if (lf >= 0 && (crlf < 0 || lf < crlf)) {
12381
- return { index: lf, length: 2 };
12382
- }
12383
- return { index: crlf, length: 4 };
12298
+ toRecord(value) {
12299
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
12300
+ ? value
12301
+ : null;
12384
12302
  }
12385
12303
  streamStartTimeoutMs() {
12386
12304
  return Math.max(1, this.options?.streamStartTimeoutMs ?? DEFAULT_TURN_STREAM_START_TIMEOUT_MS);
@@ -12394,27 +12312,6 @@ class PageBuilderAgenticAuthoringService {
12394
12312
  streamSilenceStatusMs() {
12395
12313
  return Math.max(0, this.options?.streamSilenceStatusMs ?? DEFAULT_TURN_STREAM_SILENCE_STATUS_MS);
12396
12314
  }
12397
- streamSilenceStatusEvent(start, elapsedMs, resultFallbackMs) {
12398
- return {
12399
- streamId: start.streamId,
12400
- threadId: start.threadId,
12401
- turnId: start.turnId,
12402
- seq: 0,
12403
- eventSchemaVersion: start.eventSchemaVersion,
12404
- timestamp: new Date().toISOString(),
12405
- type: 'status',
12406
- payload: {
12407
- phase: 'stream.waiting',
12408
- summary: 'Still waiting for the backend authoring result...',
12409
- diagnostics: {
12410
- source: 'frontend-stream-silence-watchdog',
12411
- elapsedMs,
12412
- resultFallbackMs,
12413
- fallbackAuthoringUrl: start.fallbackAuthoringUrl ?? null,
12414
- },
12415
- },
12416
- };
12417
- }
12418
12315
  streamLifecycleStatusEvent(start, phase, diagnostics) {
12419
12316
  return {
12420
12317
  streamId: start.streamId,
@@ -12445,44 +12342,6 @@ class PageBuilderAgenticAuthoringService {
12445
12342
  cause,
12446
12343
  };
12447
12344
  }
12448
- buildStreamUrl(start) {
12449
- const url = new URL(`${this.baseUrl}/turn/stream/${start.streamId}`, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
12450
- if (start.streamAccessToken) {
12451
- url.searchParams.set('accessToken', start.streamAccessToken);
12452
- }
12453
- return /^https?:\/\//i.test(this.baseUrl)
12454
- ? url.toString()
12455
- : url.pathname + url.search;
12456
- }
12457
- buildStreamProbeUrl(start) {
12458
- const url = new URL(`${this.baseUrl}/turn/stream/${start.streamId}/probe`, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
12459
- if (start.streamAccessToken) {
12460
- url.searchParams.set('accessToken', start.streamAccessToken);
12461
- }
12462
- return /^https?:\/\//i.test(this.baseUrl)
12463
- ? url.toString()
12464
- : url.pathname + url.search;
12465
- }
12466
- createEventSource(url) {
12467
- const factory = this.options?.eventSourceFactory;
12468
- const options = { withCredentials: true };
12469
- if (factory) {
12470
- return factory(url, options);
12471
- }
12472
- return new EventSource(url, options);
12473
- }
12474
- async probeTurnStreamEndpoint(url, abort) {
12475
- if (typeof fetch === 'undefined') {
12476
- return null;
12477
- }
12478
- const response = await fetch(url, {
12479
- method: 'GET',
12480
- credentials: 'include',
12481
- cache: 'no-store',
12482
- signal: abort?.signal,
12483
- });
12484
- return response.status;
12485
- }
12486
12345
  formatEtag(etag) {
12487
12346
  const trimmed = etag.trim();
12488
12347
  return trimmed.startsWith('"') ? trimmed : `"${trimmed}"`;
@@ -14144,6 +14003,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14144
14003
  service;
14145
14004
  context;
14146
14005
  mode = 'agentic-authoring';
14006
+ runtimeRelatedSurfaceDisambiguationContext = null;
14147
14007
  constructor(service, context) {
14148
14008
  this.service = service;
14149
14009
  this.context = context;
@@ -14199,6 +14059,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14199
14059
  state: 'success',
14200
14060
  phase: 'summarize',
14201
14061
  assistantMessage: intentAssistantMessage,
14062
+ assistantContent: this.toJsonObject(intentResolution.assistantContent),
14202
14063
  quickReplies,
14203
14064
  canApply: false,
14204
14065
  statusText: '',
@@ -14213,6 +14074,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14213
14074
  state: 'clarification',
14214
14075
  phase: 'clarify',
14215
14076
  assistantMessage: intentAssistantMessage,
14077
+ assistantContent: this.toJsonObject(intentResolution.assistantContent),
14216
14078
  quickReplies,
14217
14079
  canApply: false,
14218
14080
  statusText: '',
@@ -14227,6 +14089,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14227
14089
  state: 'clarification',
14228
14090
  phase: 'clarify',
14229
14091
  assistantMessage: intentAssistantMessage,
14092
+ assistantContent: this.toJsonObject(intentResolution.assistantContent),
14230
14093
  quickReplies,
14231
14094
  canApply: false,
14232
14095
  statusText: '',
@@ -14351,7 +14214,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14351
14214
  phase: 'contextualize',
14352
14215
  assistantMessage: undefined,
14353
14216
  canApply: false,
14354
- statusText: this.context.tx('agentic.status.preparingTurnStream', 'Preparing the AI authoring context...'),
14217
+ statusText: this.context.tx('agentic.status.preparingTurnStream', 'Organizando as informações do pedido...'),
14355
14218
  errorText: '',
14356
14219
  preview: null,
14357
14220
  };
@@ -14362,7 +14225,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14362
14225
  phase: 'contextualize',
14363
14226
  assistantMessage: undefined,
14364
14227
  canApply: false,
14365
- statusText: this.context.tx('agentic.status.turnStreamContextReady', 'AI authoring context is ready. Starting backend stream...'),
14228
+ statusText: this.context.tx('agentic.status.turnStreamContextReady', 'Informações prontas. Preparando a resposta...'),
14366
14229
  errorText: '',
14367
14230
  preview: null,
14368
14231
  diagnostics: {
@@ -14376,7 +14239,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14376
14239
  phase: 'contextualize',
14377
14240
  assistantMessage: undefined,
14378
14241
  canApply: false,
14379
- statusText: this.context.tx('agentic.status.preparingTurnStreamWaiting', 'Still preparing the AI authoring stream. Checking catalog, context, and backend availability...'),
14242
+ statusText: this.context.tx('agentic.status.preparingTurnStreamWaiting', 'Ainda conferindo domínio, tela atual e fontes disponíveis...'),
14380
14243
  errorText: '',
14381
14244
  preview: null,
14382
14245
  diagnostics: {
@@ -14392,7 +14255,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14392
14255
  return {
14393
14256
  state: 'listening',
14394
14257
  phase: 'capture',
14395
- assistantMessage: this.context.tx('agentic.status.cancelled', 'Request cancelled.'),
14258
+ assistantMessage: this.context.tx('agentic.status.cancelled', 'Pedido cancelado.'),
14396
14259
  quickReplies: [],
14397
14260
  canApply: false,
14398
14261
  statusText: '',
@@ -15288,15 +15151,86 @@ class PageBuilderAgenticAuthoringTurnFlow {
15288
15151
  }
15289
15152
  return JSON.parse(JSON.stringify(value));
15290
15153
  }
15154
+ captureRuntimeRelatedSurfaceDisambiguationContext(payload, event) {
15155
+ const disambiguation = this.findRuntimeRelatedSurfaceDisambiguation(payload);
15156
+ const rawOptions = Array.isArray(disambiguation?.['options'])
15157
+ ? disambiguation['options']
15158
+ : [];
15159
+ const options = rawOptions
15160
+ .map((option) => this.toJsonObject(option))
15161
+ .filter((option) => !!option)
15162
+ .filter((option) => !!this.readString(option, 'surfaceRef')
15163
+ && this.readString(option, 'optionRef') === `runtime-surface-option:${this.readString(option, 'surfaceRef')}`
15164
+ && this.readString(option, 'candidateRef').startsWith('runtime-surface-candidate:'))
15165
+ .slice(0, 4)
15166
+ .map((option) => ({
15167
+ surfaceRef: this.readString(option, 'surfaceRef'),
15168
+ optionRef: this.readString(option, 'optionRef'),
15169
+ candidateRef: this.readString(option, 'candidateRef'),
15170
+ label: this.readString(option, 'label') || this.readString(option, 'surfaceRef'),
15171
+ semanticAliases: Array.isArray(option['semanticAliases'])
15172
+ ? option['semanticAliases']
15173
+ .filter((alias) => typeof alias === 'string' && !!alias.trim())
15174
+ .map((alias) => alias.trim())
15175
+ .slice(0, 12)
15176
+ : [],
15177
+ }));
15178
+ if (options.length < 2) {
15179
+ return;
15180
+ }
15181
+ const evidenceBundle = this.toJsonObject(payload['evidenceBundle']);
15182
+ const runtimeContext = this.toJsonObject(evidenceBundle?.['runtimeConsultableContext'])
15183
+ ?? this.toJsonObject(evidenceBundle?.['runtimeContext'])
15184
+ ?? null;
15185
+ this.runtimeRelatedSurfaceDisambiguationContext = {
15186
+ schemaVersion: 'praxis-runtime-related-surface-disambiguation-context.v1',
15187
+ source: 'runtimeRelatedSurfaceDisambiguation',
15188
+ authority: 'grounding_only',
15189
+ sessionId: event?.threadId ?? '',
15190
+ sourceTurnId: event?.turnId ?? '',
15191
+ pageId: this.readString(runtimeContext, 'pageId'),
15192
+ capturedAt: new Date().toISOString(),
15193
+ ttlMs: 300000,
15194
+ optionCount: options.length,
15195
+ options,
15196
+ rawRuntimeValuesCopied: false,
15197
+ };
15198
+ }
15199
+ findRuntimeRelatedSurfaceDisambiguation(value) {
15200
+ const root = this.toJsonObject(value);
15201
+ if (!root) {
15202
+ return null;
15203
+ }
15204
+ if (root['schemaVersion'] === 'praxis-runtime-related-surface-disambiguation.v1') {
15205
+ return root;
15206
+ }
15207
+ for (const child of Object.values(root)) {
15208
+ if (Array.isArray(child)) {
15209
+ for (const item of child) {
15210
+ const found = this.findRuntimeRelatedSurfaceDisambiguation(item);
15211
+ if (found) {
15212
+ return found;
15213
+ }
15214
+ }
15215
+ }
15216
+ else {
15217
+ const found = this.findRuntimeRelatedSurfaceDisambiguation(child);
15218
+ if (found) {
15219
+ return found;
15220
+ }
15221
+ }
15222
+ }
15223
+ return null;
15224
+ }
15291
15225
  async buildTurnStreamRequest(request, prompt) {
15292
15226
  const startedAt = Date.now();
15293
- const capabilitiesStartedAt = Date.now();
15294
- const componentCapabilities = await this.context.loadComponentCapabilities();
15295
- const capabilitiesElapsedMs = Math.max(0, Date.now() - capabilitiesStartedAt);
15296
15227
  const authoringContextStartedAt = Date.now();
15297
15228
  const selectedWidgetKey = this.context.selectedWidgetKey();
15298
15229
  const authoringContext = this.buildAuthoringContext(request);
15299
15230
  const authoringContextElapsedMs = Math.max(0, Date.now() - authoringContextStartedAt);
15231
+ const runtimeObservationsStartedAt = Date.now();
15232
+ const runtimeObservationResult = await this.collectRuntimeComponentObservations(request);
15233
+ const runtimeObservationsElapsedMs = Math.max(0, Date.now() - runtimeObservationsStartedAt);
15300
15234
  const streamRequest = {
15301
15235
  userPrompt: prompt,
15302
15236
  targetApp: this.context.targetApp,
@@ -15307,8 +15241,20 @@ class PageBuilderAgenticAuthoringTurnFlow {
15307
15241
  provider: this.context.provider(),
15308
15242
  model: this.context.model(),
15309
15243
  apiKey: this.context.apiKey(),
15310
- componentCapabilities,
15311
15244
  ...authoringContext,
15245
+ ...(this.runtimeRelatedSurfaceDisambiguationContext
15246
+ ? {
15247
+ diagnostics: {
15248
+ runtimeRelatedSurfaceDisambiguationContext: this.cloneJsonObject(this.runtimeRelatedSurfaceDisambiguationContext),
15249
+ },
15250
+ }
15251
+ : {}),
15252
+ ...(runtimeObservationResult.observations.length
15253
+ ? {
15254
+ runtimeComponentObservations: runtimeObservationResult.observations,
15255
+ runtimeComponentObservationTrustBoundary: 'untrusted_frontend_observation',
15256
+ }
15257
+ : {}),
15312
15258
  };
15313
15259
  return {
15314
15260
  streamRequest,
@@ -15316,21 +15262,48 @@ class PageBuilderAgenticAuthoringTurnFlow {
15316
15262
  schemaVersion: 'praxis-turn-stream-preparation-diagnostics.v1',
15317
15263
  source: 'page-builder-agentic-authoring-turn-flow',
15318
15264
  totalElapsedMs: Math.max(0, Date.now() - startedAt),
15319
- capabilitiesElapsedMs,
15265
+ componentCapabilitiesSource: 'server-resolved',
15320
15266
  authoringContextElapsedMs,
15321
- catalogCount: componentCapabilities.catalogs?.length ?? 0,
15322
- capabilityCount: componentCapabilities.catalogs
15323
- .reduce((count, catalog) => count + (catalog.capabilities?.length ?? 0), 0),
15267
+ runtimeObservationsElapsedMs,
15324
15268
  attachmentCount: authoringContext.attachmentSummaries?.length ?? 0,
15325
15269
  hasPendingClarification: !!authoringContext.pendingClarification,
15326
15270
  hasContextHints: !!authoringContext.contextHints,
15271
+ runtimeObservationCount: runtimeObservationResult.observations.length,
15272
+ runtimeObservationSource: runtimeObservationResult.source,
15273
+ runtimeObservationUnavailable: runtimeObservationResult.unavailable,
15327
15274
  },
15328
15275
  };
15329
15276
  }
15277
+ async collectRuntimeComponentObservations(request) {
15278
+ try {
15279
+ const collected = await this.context.collectRuntimeComponentObservations?.();
15280
+ if (collected?.length) {
15281
+ return {
15282
+ observations: collected,
15283
+ source: 'page-builder-explicit',
15284
+ unavailable: false,
15285
+ };
15286
+ }
15287
+ }
15288
+ catch {
15289
+ const fallback = request.runtimeComponentObservations || [];
15290
+ return {
15291
+ observations: fallback,
15292
+ source: fallback.length ? 'assistant-request' : 'none',
15293
+ unavailable: true,
15294
+ };
15295
+ }
15296
+ const fallback = request.runtimeComponentObservations || [];
15297
+ return {
15298
+ observations: fallback,
15299
+ source: fallback.length ? 'assistant-request' : 'none',
15300
+ unavailable: false,
15301
+ };
15302
+ }
15330
15303
  async toTurnResultFromStreamEvent(event, request, prompt) {
15331
15304
  const payload = this.toJsonObject(event.payload) ?? {};
15332
15305
  if (event.type === 'result') {
15333
- return this.toResultTurnFromStreamPayload(payload, request, prompt);
15306
+ return this.toResultTurnFromStreamPayload(payload, request, prompt, event);
15334
15307
  }
15335
15308
  if (event.type === 'error') {
15336
15309
  const message = this.describeStreamError(payload);
@@ -15349,7 +15322,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15349
15322
  return {
15350
15323
  state: 'listening',
15351
15324
  phase: 'capture',
15352
- assistantMessage: this.context.tx('agentic.status.cancelled', 'Request cancelled.'),
15325
+ assistantMessage: this.context.tx('agentic.status.cancelled', 'Pedido cancelado.'),
15353
15326
  quickReplies: [],
15354
15327
  canApply: false,
15355
15328
  statusText: '',
@@ -15368,7 +15341,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15368
15341
  preview: null,
15369
15342
  };
15370
15343
  }
15371
- async toResultTurnFromStreamPayload(payload, request, prompt) {
15344
+ async toResultTurnFromStreamPayload(payload, request, prompt, event) {
15372
15345
  const intentResolution = this.normalizeIntentResolutionResult(payload['intentResolution']);
15373
15346
  const preview = payload['preview'];
15374
15347
  if (!intentResolution) {
@@ -15390,7 +15363,11 @@ class PageBuilderAgenticAuthoringTurnFlow {
15390
15363
  ? payload['quickReplies']
15391
15364
  : intentResolution.quickReplies ?? [];
15392
15365
  const quickReplies = this.resolveShellQuickReplies(intentResolution, rawQuickReplies);
15366
+ this.captureRuntimeRelatedSurfaceDisambiguationContext(payload, event);
15393
15367
  const assistantMessage = this.normalizeAssistantMessageForQuickReplies(rawAssistantMessage, quickReplies);
15368
+ const assistantContent = this.toJsonObject(payload['assistantContent'])
15369
+ ?? this.toJsonObject(intentResolution.assistantContent)
15370
+ ?? null;
15394
15371
  const canApply = payload['canApply'] === true && !!preview?.valid;
15395
15372
  const contextualExecutableIntent = request
15396
15373
  ? this.toExecutableContextualComponentIntent(intentResolution, request)
@@ -15429,7 +15406,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15429
15406
  state: 'review',
15430
15407
  phase: 'review',
15431
15408
  assistantMessage: status,
15432
- quickReplies: this.mergeDashboardQualityQuickReplies(quickReplies, intentResolution, preview),
15409
+ quickReplies: this.governedBlockedReviewQuickReplies(quickReplies, intentResolution, preview),
15433
15410
  canApply: false,
15434
15411
  statusText: this.reviewStatusText(status, false),
15435
15412
  errorText: '',
@@ -15456,6 +15433,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15456
15433
  state: pendingClarification || requiresChoice ? 'clarification' : 'success',
15457
15434
  phase: pendingClarification || requiresChoice ? 'clarify' : 'summarize',
15458
15435
  assistantMessage,
15436
+ assistantContent,
15459
15437
  quickReplies,
15460
15438
  canApply: false,
15461
15439
  statusText: '',
@@ -16098,26 +16076,35 @@ class PageBuilderAgenticAuthoringTurnFlow {
16098
16076
  ? this.mergeDashboardQualityQuickReplies(quickReplies, intentResolution, preview)
16099
16077
  : [...quickReplies];
16100
16078
  }
16079
+ governedBlockedReviewQuickReplies(quickReplies, intentResolution, preview) {
16080
+ const replies = this.reviewQuickReplies(quickReplies, intentResolution, preview);
16081
+ if (intentResolution.artifactKind === 'dashboard'
16082
+ && !this.dashboardReviewCanApply(intentResolution, preview)
16083
+ && replies.length === 0) {
16084
+ return [this.dashboardQualityFallbackQuickReply(intentResolution, preview)];
16085
+ }
16086
+ return replies;
16087
+ }
16101
16088
  describeDashboardQualityWarning(code) {
16102
16089
  switch (code) {
16103
16090
  case 'dashboard-without-chart-widget':
16104
- return this.context.tx('agentic.dashboardQuality.warning.chart', 'chart widget missing');
16091
+ return this.context.tx('agentic.dashboardQuality.warning.chart', 'faltou um gráfico');
16105
16092
  case 'dashboard-without-kpi-widget':
16106
- return this.context.tx('agentic.dashboardQuality.warning.kpi', 'KPI block missing');
16093
+ return this.context.tx('agentic.dashboardQuality.warning.kpi', 'faltaram indicadores');
16107
16094
  case 'dashboard-kpi-placeholder-values':
16108
- return this.context.tx('agentic.dashboardQuality.warning.kpiValues', 'KPI values are placeholders');
16095
+ return this.context.tx('agentic.dashboardQuality.warning.kpiValues', 'indicadores ainda estão sem dados reais');
16109
16096
  case 'dashboard-without-filter-widget':
16110
- return this.context.tx('agentic.dashboardQuality.warning.filter', 'filter widget missing');
16097
+ return this.context.tx('agentic.dashboardQuality.warning.filter', 'faltaram filtros');
16111
16098
  case 'dashboard-without-record-detail-widget':
16112
- return this.context.tx('agentic.dashboardQuality.warning.details', 'record detail widget missing');
16099
+ return this.context.tx('agentic.dashboardQuality.warning.details', 'faltou uma área de detalhe');
16113
16100
  case 'dashboard-without-composition-links':
16114
- return this.context.tx('agentic.dashboardQuality.warning.links', 'widget interactions missing');
16101
+ return this.context.tx('agentic.dashboardQuality.warning.links', 'faltou conectar as partes do painel');
16115
16102
  case 'dashboard-filter-not-connected':
16116
- return this.context.tx('agentic.dashboardQuality.warning.filterConnection', 'filter is not connected');
16103
+ return this.context.tx('agentic.dashboardQuality.warning.filterConnection', 'o filtro ainda não controla o painel');
16117
16104
  case 'dashboard-chart-not-interactive':
16118
- return this.context.tx('agentic.dashboardQuality.warning.chartInteraction', 'chart interaction missing');
16105
+ return this.context.tx('agentic.dashboardQuality.warning.chartInteraction', 'o gráfico ainda não abre detalhes');
16119
16106
  case 'dashboard-without-surface-actions':
16120
- return this.context.tx('agentic.dashboardQuality.warning.surfaces', 'surface actions missing');
16107
+ return this.context.tx('agentic.dashboardQuality.warning.surfaces', 'faltaram ações para consultar detalhes');
16121
16108
  default:
16122
16109
  return code;
16123
16110
  }
@@ -16163,8 +16150,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16163
16150
  if (warnings.includes('dashboard-without-kpi-widget')) {
16164
16151
  replies.push(this.dashboardQualityQuickReply({
16165
16152
  id: 'dashboard-quality-add-kpis',
16166
- label: this.context.tx('agentic.dashboardQuality.quickReply.addKpis', 'Add KPIs'),
16167
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addKpis', 'Add a compact KPI block with the most useful metrics for this dashboard, preferably using praxis-rich-content statGroup or metric nodes.'),
16153
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addKpis', 'Adicionar indicadores'),
16154
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addKpis', 'Inclua um bloco compacto com os indicadores mais úteis para acompanhar esse painel.'),
16168
16155
  icon: 'monitoring',
16169
16156
  changeKind: 'add_dashboard_kpis',
16170
16157
  contextHints,
@@ -16173,8 +16160,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16173
16160
  if (warnings.includes('dashboard-kpi-placeholder-values')) {
16174
16161
  replies.push(this.dashboardQualityQuickReply({
16175
16162
  id: 'dashboard-quality-bind-kpis',
16176
- label: this.context.tx('agentic.dashboardQuality.quickReply.bindKpis', 'Bind KPI values'),
16177
- prompt: this.context.tx('agentic.dashboardQuality.prompt.bindKpis', 'Replace placeholder KPI values with real metric bindings from the dashboard DTO/source, keeping labels and formatting human-readable.'),
16163
+ label: this.context.tx('agentic.dashboardQuality.quickReply.bindKpis', 'Usar dados reais nos indicadores'),
16164
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.bindKpis', 'Substitua valores de exemplo dos indicadores por dados reais da fonte escolhida, mantendo nomes e formatos fáceis de entender.'),
16178
16165
  icon: 'data_object',
16179
16166
  changeKind: 'bind_dashboard_kpis',
16180
16167
  contextHints,
@@ -16183,8 +16170,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16183
16170
  if (warnings.includes('dashboard-without-filter-widget')) {
16184
16171
  replies.push(this.dashboardQualityQuickReply({
16185
16172
  id: 'dashboard-quality-add-filters',
16186
- label: this.context.tx('agentic.dashboardQuality.quickReply.addFilters', 'Add filters'),
16187
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addFilters', 'Add canonical dashboard filters from the DTO fields and connect their requestSearch output to charts and detail widgets through queryContext.'),
16173
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addFilters', 'Adicionar filtros'),
16174
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addFilters', 'Adicione filtros úteis para o analista refinar os dados do painel.'),
16188
16175
  icon: 'filter_alt',
16189
16176
  changeKind: 'add_dashboard_filters',
16190
16177
  contextHints,
@@ -16193,8 +16180,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16193
16180
  if (warnings.includes('dashboard-without-chart-widget')) {
16194
16181
  replies.push(this.dashboardQualityQuickReply({
16195
16182
  id: 'dashboard-quality-add-chart',
16196
- label: this.context.tx('agentic.dashboardQuality.quickReply.addChart', 'Add chart'),
16197
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addChart', 'Add the most relevant analytical chart to this dashboard, using the same data source and connecting it to the detail widgets.'),
16183
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addChart', 'Adicionar gráfico'),
16184
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addChart', 'Adicione o gráfico mais útil para explicar os dados desse painel e conecte-o aos detalhes quando possível.'),
16198
16185
  icon: 'insert_chart',
16199
16186
  changeKind: 'add_dashboard_chart',
16200
16187
  contextHints,
@@ -16203,8 +16190,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16203
16190
  if (warnings.includes('dashboard-without-record-detail-widget')) {
16204
16191
  replies.push(this.dashboardQualityQuickReply({
16205
16192
  id: 'dashboard-quality-add-details',
16206
- label: this.context.tx('agentic.dashboardQuality.quickReply.addDetails', 'Add details'),
16207
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addDetails', 'Add a rich record detail widget, preferably a Praxis list or table, using the same dashboard data source.'),
16193
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addDetails', 'Adicionar detalhes'),
16194
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addDetails', 'Inclua uma área de detalhes para o analista consultar os registros por trás dos indicadores.'),
16208
16195
  icon: 'view_list',
16209
16196
  changeKind: 'add_dashboard_detail_widget',
16210
16197
  contextHints,
@@ -16215,8 +16202,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16215
16202
  || warnings.includes('dashboard-chart-not-interactive')) {
16216
16203
  replies.push(this.dashboardQualityQuickReply({
16217
16204
  id: 'dashboard-quality-connect-widgets',
16218
- label: this.context.tx('agentic.dashboardQuality.quickReply.connectWidgets', 'Connect widgets'),
16219
- prompt: this.context.tx('agentic.dashboardQuality.prompt.connectWidgets', 'Connect the dashboard widgets so filter and chart selections update the detail widgets through queryContext.'),
16205
+ label: this.context.tx('agentic.dashboardQuality.quickReply.connectWidgets', 'Conectar painel e detalhes'),
16206
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.connectWidgets', 'Faça filtros e escolhas no gráfico atualizarem a área de detalhes do painel.'),
16220
16207
  icon: 'hub',
16221
16208
  changeKind: 'connect_dashboard_widgets',
16222
16209
  contextHints,
@@ -16225,8 +16212,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16225
16212
  if (warnings.includes('dashboard-without-surface-actions')) {
16226
16213
  replies.push(this.dashboardQualityQuickReply({
16227
16214
  id: 'dashboard-quality-add-surfaces',
16228
- label: this.context.tx('agentic.dashboardQuality.quickReply.addSurfaces', 'Add surfaces'),
16229
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addSurfaces', 'Add surface.open actions so dashboard selections can open richer drill-down details in a modal or drawer.'),
16215
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addSurfaces', 'Abrir detalhes relacionados'),
16216
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addSurfaces', 'Permita abrir detalhes relacionados a partir das seleções do painel, sem expor termos técnicos ao usuário.'),
16230
16217
  icon: 'open_in_new',
16231
16218
  changeKind: 'add_dashboard_surfaces',
16232
16219
  contextHints,
@@ -16329,6 +16316,34 @@ class PageBuilderAgenticAuthoringTurnFlow {
16329
16316
  },
16330
16317
  };
16331
16318
  }
16319
+ dashboardQualityFallbackQuickReply(intentResolution, preview) {
16320
+ const diagnostics = this.buildDashboardAuthoringDiagnostics(intentResolution, preview);
16321
+ const validation = this.toJsonObject(diagnostics?.['validation']);
16322
+ const warnings = this.arrayFromUnknown(validation?.['warnings']).map((warning) => `${warning}`);
16323
+ const selectedCandidate = this.toJsonObject(intentResolution.selectedCandidate);
16324
+ const target = this.toJsonObject(intentResolution.target);
16325
+ const resourcePath = this.readString(this.toJsonObject(diagnostics?.['dto']) ?? {}, 'resourcePath')
16326
+ || this.readString(selectedCandidate, 'resourcePath')
16327
+ || this.readString(target, 'resourcePath')
16328
+ || '';
16329
+ const dashboardQuality = this.toDashboardQualityRepairContext(diagnostics);
16330
+ return this.dashboardQualityQuickReply({
16331
+ id: 'dashboard-quality-refine',
16332
+ label: this.context.tx('agentic.dashboardQuality.quickReply.refine', 'Refinar painel'),
16333
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.refine', 'Ajuste o painel para resolver os pontos pendentes e manter apenas decisões compatíveis com os dados confirmados.'),
16334
+ icon: 'auto_fix_high',
16335
+ changeKind: 'refine_dashboard_quality',
16336
+ contextHints: {
16337
+ source: 'dashboard-quality-gate',
16338
+ kind: 'dashboard-repair-action',
16339
+ artifactKind: 'dashboard',
16340
+ resourcePath,
16341
+ warnings,
16342
+ ...(dashboardQuality ? { dashboardQuality } : {}),
16343
+ ...this.dashboardRepairSnapshot(preview),
16344
+ },
16345
+ });
16346
+ }
16332
16347
  phaseForStreamPayload(payload) {
16333
16348
  const phase = this.readString(payload, 'phase');
16334
16349
  if (phase === 'intent.resolve')
@@ -16348,45 +16363,45 @@ class PageBuilderAgenticAuthoringTurnFlow {
16348
16363
  let status = null;
16349
16364
  switch (phase) {
16350
16365
  case 'context.bundle':
16351
- status = this.context.tx('agentic.status.contextBundle', 'Preparing context...');
16366
+ status = this.context.tx('agentic.status.contextBundle', 'Organizando informações...');
16352
16367
  break;
16353
16368
  case 'intent.resolve':
16354
16369
  if (this.isSecondPassStreamPayload(payload)) {
16355
- status = this.context.tx('agentic.status.refinedCandidates', 'Reviewing the retrieved resources with the AI...');
16370
+ status = this.context.tx('agentic.status.refinedCandidates', 'Conferindo as fontes encontradas...');
16356
16371
  break;
16357
16372
  }
16358
- status = this.context.tx('agentic.status.resolvingIntent', 'Resolving intent...');
16373
+ status = this.context.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...');
16359
16374
  break;
16360
16375
  case 'resource.discovery':
16361
16376
  if (this.isBackendResourceDiscoveryPayload(payload)) {
16362
- status = this.context.tx('agentic.status.resourceDiscoveryBackend', 'Found API resources in the backend catalog.');
16377
+ status = this.context.tx('agentic.status.resourceDiscoveryBackend', 'Encontrei fontes de dados no catálogo do domínio.');
16363
16378
  break;
16364
16379
  }
16365
- status = this.context.tx('agentic.status.resourceDiscovery', 'Finding API resources...');
16380
+ status = this.context.tx('agentic.status.resourceDiscovery', 'Buscando fontes de dados...');
16366
16381
  break;
16367
16382
  case 'projectKnowledge.retrieve':
16368
16383
  status = this.projectKnowledgeStatusForStreamPayload(payload);
16369
16384
  break;
16370
16385
  case 'preview.plan':
16371
- status = this.context.tx('agentic.status.previewing', 'Generating preview...');
16386
+ status = this.context.tx('agentic.status.previewing', 'Criando prévia...');
16372
16387
  break;
16373
16388
  case 'preview.compile':
16374
- status = this.context.tx('agentic.status.previewCompile', 'Compiling preview...');
16389
+ status = this.context.tx('agentic.status.previewCompile', 'Montando a tela...');
16375
16390
  break;
16376
16391
  case 'stream.waiting':
16377
- status = this.context.tx('agentic.status.streamWaiting', 'The backend is still working on this dashboard. Keeping the request alive...');
16392
+ status = this.context.tx('agentic.status.streamWaiting', 'Ainda estou montando este painel. Mantendo o pedido em andamento...');
16378
16393
  break;
16379
16394
  case 'stream.start.accepted':
16380
- status = this.context.tx('agentic.status.streamStartAccepted', 'Backend accepted the authoring stream. Opening live progress...');
16395
+ status = this.context.tx('agentic.status.streamStartAccepted', 'Pedido recebido. Abrindo o acompanhamento da criação...');
16381
16396
  break;
16382
16397
  case 'stream.probe.ready':
16383
- status = this.context.tx('agentic.status.streamProbeReady', 'Authoring stream endpoint is reachable.');
16398
+ status = this.context.tx('agentic.status.streamProbeReady', 'Acompanhamento da criação disponível.');
16384
16399
  break;
16385
16400
  case 'stream.transport.opening':
16386
- status = this.context.tx('agentic.status.streamTransportOpening', 'Opening the live authoring stream...');
16401
+ status = this.context.tx('agentic.status.streamTransportOpening', 'Abrindo acompanhamento em tempo real...');
16387
16402
  break;
16388
16403
  case 'stream.first-event.received':
16389
- status = this.context.tx('agentic.status.streamFirstEventReceived', 'Live authoring progress started.');
16404
+ status = this.context.tx('agentic.status.streamFirstEventReceived', 'Criação iniciada.');
16390
16405
  break;
16391
16406
  default:
16392
16407
  status = this.readString(payload, 'summary') || this.readString(payload, 'message');
@@ -16403,17 +16418,17 @@ class PageBuilderAgenticAuthoringTurnFlow {
16403
16418
  return status;
16404
16419
  }
16405
16420
  return this.context
16406
- .tx('agentic.status.backendProgressElapsed', '{status} Backend still working for {seconds}s.')
16421
+ .tx('agentic.status.backendProgressElapsed', '{status} Ainda trabalhando nisso {seconds}s.')
16407
16422
  .replace('{status}', status)
16408
16423
  .replace('{seconds}', `${Math.round(elapsedSeconds)}`);
16409
16424
  }
16410
16425
  projectKnowledgeStatusForStreamPayload(payload) {
16411
16426
  const diagnostics = this.toJsonObject(payload['diagnostics']);
16412
16427
  const influenceCount = this.readNumber(diagnostics ?? {}, 'influenceCount');
16413
- const base = this.context.tx('agentic.status.projectKnowledgeRetrieved', 'Retrieved governed project knowledge for this authoring turn.');
16428
+ const base = this.context.tx('agentic.status.projectKnowledgeRetrieved', 'Encontrei conhecimento governado do projeto para orientar este pedido.');
16414
16429
  if (influenceCount && influenceCount > 0) {
16415
16430
  return this.context
16416
- .tx('agentic.status.projectKnowledgeRetrievedCount', 'Retrieved {count} governed project knowledge signals for this authoring turn.')
16431
+ .tx('agentic.status.projectKnowledgeRetrievedCount', 'Encontrei {count} sinais governados do projeto para orientar este pedido.')
16417
16432
  .replace('{count}', String(influenceCount));
16418
16433
  }
16419
16434
  return base;
@@ -16424,8 +16439,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16424
16439
  return normalized;
16425
16440
  }
16426
16441
  return canApply
16427
- ? this.context.tx('agentic.status.reviewReady', 'Ready for review.')
16428
- : this.context.tx('agentic.status.reviewNeedsAttention', 'Review the pending points before saving.');
16442
+ ? this.context.tx('agentic.status.reviewReady', 'Pronto para revisão.')
16443
+ : this.context.tx('agentic.status.reviewNeedsAttention', 'Revise os pontos pendentes antes de salvar.');
16429
16444
  }
16430
16445
  shouldReplaceReviewStatus(status) {
16431
16446
  const normalized = status.toLocaleLowerCase();
@@ -16446,13 +16461,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
16446
16461
  describeStreamError(payload) {
16447
16462
  const code = this.readString(payload, 'code');
16448
16463
  if (code === 'agentic-authoring-timeout') {
16449
- return this.context.tx('agentic.errors.streamTimeout', 'The assistant took too long to finish this request. Try again with a narrower request or review the active context.');
16464
+ return this.context.tx('agentic.errors.streamTimeout', 'O assistente demorou para concluir este pedido. Tente de novo com um recorte menor ou revise o contexto ativo.');
16450
16465
  }
16451
16466
  if (code === 'agentic-authoring-processing-failed') {
16452
- return this.context.tx('agentic.errors.streamProcessing', 'The assistant could not finish this authoring request. Try again or ask support to review the diagnostics.');
16467
+ return this.context.tx('agentic.errors.streamProcessing', 'Não consegui concluir este pedido. Tente novamente ou peça uma revisão dos detalhes.');
16453
16468
  }
16454
16469
  return this.readString(payload, 'assistantMessage')
16455
- || this.context.tx('agentic.errors.generic', 'AI authoring failed.');
16470
+ || this.context.tx('agentic.errors.generic', 'Não consegui concluir este pedido.');
16456
16471
  }
16457
16472
  toTurnStreamTransportErrorResult(error) {
16458
16473
  const message = this.isTurnStreamConnectionError(error)
@@ -16529,7 +16544,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
16529
16544
  toGovernedRouteFailClosedResult(request, prompt, error) {
16530
16545
  const contextHints = this.buildContextHints(request);
16531
16546
  const domainCatalog = this.toJsonObject(contextHints?.['domainCatalog']);
16532
- const assistantMessage = this.context.tx('agentic.governedRoute.streamUnavailable', 'This request must continue through the governed semantic-decision flow in /api/praxis/config/domain-rules. The backend stream is unavailable, so local preview/apply is blocked.');
16547
+ const assistantMessage = this.context.tx('agentic.governedRoute.streamUnavailable', 'Este pedido precisa continuar pela revisão governada da regra de negócio. Não vou criar uma prévia local enquanto essa revisão não estiver disponível.');
16533
16548
  const intentResolution = {
16534
16549
  valid: false,
16535
16550
  operationKind: 'route',
@@ -16743,9 +16758,9 @@ class PageBuilderAgenticAuthoringTurnFlow {
16743
16758
  return backendText;
16744
16759
  }
16745
16760
  const firstLabel = quickReplies[0]?.label?.trim()
16746
- || this.context.tx('agentic.resourceDiscovery.defaultRecommendedLabel', 'the first option');
16761
+ || this.context.tx('agentic.resourceDiscovery.defaultRecommendedLabel', 'a primeira opção');
16747
16762
  const sourceCount = this.resourceDiscoverySourceCountLabel(quickReplies.length);
16748
- return this.context.tx('agentic.resourceDiscovery.found', 'I found {sourceCount} for this screen. I recommend starting with {first} because it is the best fit for charts, KPIs, and drill-down. Review the cards below to see what each source is good for, what it returns, and what I will create after you select it.')
16763
+ return this.context.tx('agentic.resourceDiscovery.found', 'Encontrei {sourceCount} para esta tela. Recomendo começar por {first}, porque parece a melhor opção para indicadores, gráficos e detalhes. Revise as opções abaixo e escolha a fonte que melhor combina com o que você quer criar.')
16749
16764
  .replace('{sourceCount}', sourceCount)
16750
16765
  .replace('{first}', firstLabel);
16751
16766
  }
@@ -17585,30 +17600,37 @@ class PageBuilderAgenticAuthoringTurnFlow {
17585
17600
  && !!String(presentation[key]).trim());
17586
17601
  }
17587
17602
  resourceQuickReplyDescription(reply) {
17603
+ const label = this.resourceQuickReplySubjectLabel(reply.label);
17588
17604
  const description = reply.description?.trim() ?? '';
17589
17605
  if (description
17590
17606
  && !this.isTechnicalResourceDescription(description)
17591
17607
  && !this.isGenericResourceDescription(description)) {
17592
17608
  return description;
17593
17609
  }
17594
- return this.context.tx('agentic.resourceDiscovery.cardDescription', 'Fonte recomendada para transformar {label} em painel: ajuda a escolher graficos, listas, filtros e formatos antes de materializar a tela.').replace('{label}', reply.label);
17610
+ return this.context.tx('agentic.resourceDiscovery.cardDescription', 'Fonte recomendada para transformar {label} em painel: ajuda a escolher graficos, listas, filtros e formatos antes de materializar a tela.').replace('{label}', label);
17595
17611
  }
17596
17612
  resourceQuickReplyPresentation(reply) {
17597
17613
  const contextHints = this.toJsonObject(reply.contextHints);
17598
17614
  const artifactKind = this.readString(contextHints, 'artifactKind');
17615
+ const label = this.resourceQuickReplySubjectLabel(reply.label);
17599
17616
  if (artifactKind === 'table') {
17600
17617
  return {
17601
- bestFor: `Boa quando voce quer transformar ${reply.label} em uma tabela navegavel.`,
17602
- returns: 'Retorna uma pre-visualizacao com colunas, filtros e fonte semantica preservada.',
17618
+ bestFor: `Boa quando você quer navegar, filtrar e comparar registros de ${label}.`,
17619
+ returns: 'Retorna uma pré-visualização com colunas, filtros e fonte semântica preservada.',
17603
17620
  nextStep: 'Clique para criar a tabela e revisar antes de salvar.',
17604
17621
  };
17605
17622
  }
17606
17623
  return {
17607
- bestFor: this.context.tx('agentic.resourceDiscovery.cardBestFor', 'Quando voce quer entender se {label} responde ao objetivo de negocio antes de criar widgets.').replace('{label}', reply.label),
17608
- returns: this.context.tx('agentic.resourceDiscovery.cardReturns', 'Sugere metricas, dimensoes, filtros, formatos de valor, graficos e listas de detalhe compativeis com a fonte.'),
17609
- nextStep: this.context.tx('agentic.resourceDiscovery.cardNextStep', 'Selecione para eu propor uma pre-visualizacao governada com cards ricos, drill-down e formatos adequados por padrao.'),
17624
+ bestFor: this.context.tx('agentic.resourceDiscovery.cardBestFor', 'Quando você precisa decidir se {label} é a melhor fonte para a experiência que está criando.').replace('{label}', label),
17625
+ returns: this.context.tx('agentic.resourceDiscovery.cardReturns', 'Sugere métricas, dimensões, filtros, formatos de valor, gráficos e listas de detalhe compatíveis com a fonte.'),
17626
+ nextStep: this.context.tx('agentic.resourceDiscovery.cardNextStep', 'Selecione para eu propor uma pré-visualização governada com cards ricos, drill-down e formatos adequados por padrão.'),
17610
17627
  };
17611
17628
  }
17629
+ resourceQuickReplySubjectLabel(label) {
17630
+ const normalized = (label || '').trim();
17631
+ return normalized.replace(/^(?:Criar\s+)?(?:tabela|gr[aá]fico|formul[aá]rio|dashboard|p[aá]gina)\s*:\s*/iu, '').trim()
17632
+ || normalized;
17633
+ }
17612
17634
  isTechnicalResourceDescription(description) {
17613
17635
  return /(?:^|\s)(?:GET|POST|PUT|PATCH|DELETE)\s+\//iu.test(description)
17614
17636
  || /\/api\//iu.test(description)
@@ -17725,15 +17747,53 @@ class PageBuilderAgenticAuthoringTurnFlow {
17725
17747
  buildContextHints(request) {
17726
17748
  const base = this.toJsonObject(request.action?.contextHints)
17727
17749
  ?? this.toJsonObject(request.contextHints);
17750
+ const normalizedBase = this.normalizeAmbientDomainCatalogContextHints(base);
17728
17751
  const includeLlmDiagnostics = this.context.includeLlmDiagnostics?.() === true;
17729
17752
  if (!includeLlmDiagnostics) {
17730
- return base ?? undefined;
17753
+ return normalizedBase ?? undefined;
17731
17754
  }
17732
17755
  return {
17733
- ...(base ?? {}),
17756
+ ...(normalizedBase ?? {}),
17734
17757
  includeLlmDiagnostics: true,
17735
17758
  };
17736
17759
  }
17760
+ normalizeAmbientDomainCatalogContextHints(contextHints) {
17761
+ if (!contextHints) {
17762
+ return null;
17763
+ }
17764
+ const domainCatalog = this.toJsonObject(contextHints['domainCatalog']);
17765
+ if (!domainCatalog || !this.isAmbientUiCompositionDomainCatalog(domainCatalog, contextHints)) {
17766
+ return contextHints;
17767
+ }
17768
+ const normalizedDomainCatalog = { ...domainCatalog };
17769
+ delete normalizedDomainCatalog['resourceKey'];
17770
+ delete normalizedDomainCatalog['query'];
17771
+ return {
17772
+ ...contextHints,
17773
+ domainCatalog: normalizedDomainCatalog,
17774
+ };
17775
+ }
17776
+ isAmbientUiCompositionDomainCatalog(domainCatalog, contextHints) {
17777
+ const recommendedFlow = this.readString(domainCatalog, 'recommendedAuthoringFlow');
17778
+ if (recommendedFlow !== 'ui_composition_authoring') {
17779
+ return false;
17780
+ }
17781
+ if (this.readString(domainCatalog, 'type') === 'governance'
17782
+ || this.readString(domainCatalog, 'recommendedRuleType')
17783
+ || this.readString(domainCatalog, 'ruleType')
17784
+ || this.readString(domainCatalog, 'domainRuleType')
17785
+ || this.readString(domainCatalog, 'targetLayer')) {
17786
+ return false;
17787
+ }
17788
+ return !this.hasExplicitResourceTarget(contextHints);
17789
+ }
17790
+ hasExplicitResourceTarget(contextHints) {
17791
+ return !!(this.readString(contextHints, 'resourcePath')
17792
+ || this.readString(contextHints, 'submitUrl')
17793
+ || this.readString(contextHints, 'schemaUrl')
17794
+ || this.readString(contextHints, 'selectedResourcePath')
17795
+ || this.readString(contextHints, 'targetResourcePath'));
17796
+ }
17737
17797
  toAttachmentSummaries(attachments) {
17738
17798
  return attachments.map((attachment) => ({
17739
17799
  id: attachment.id,
@@ -17834,13 +17894,13 @@ function deriveSharedRuleContinuationActions(input) {
17834
17894
  return status === 'applied' || status === 'active';
17835
17895
  });
17836
17896
  return [
17837
- sharedRuleAction('open_definition', 'Create definition', 'Create or open the governed definition.', target, enabledWhen(!busy && hasAuthoringTarget && !definitionId, busy ? 'busy' : definitionId ? 'definition_already_available' : !handoff ? 'missing_handoff' : 'missing_authoring_target')),
17838
- sharedRuleAction('simulate', 'Simulate', 'Run canonical backend simulation before publication.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17839
- sharedRuleAction('approve', 'Approve', 'Approve the governed definition after review.', target, enabledWhen(!busy && !!definitionId && definitionStatus !== 'approved' && definitionStatus !== 'active', busy ? 'busy' : !definitionId ? 'missing_definition' : 'definition_already_available')),
17840
- sharedRuleAction('publish', 'Publish/materialize', 'Publish the decision and derive eligible runtime materializations.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17841
- sharedRuleAction('materialize', 'Inspect materializations', 'Inspect derived materializations without making the UI the source of truth.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17842
- sharedRuleAction('validate_enforcement', 'Validate enforcement', 'Check whether applied materializations are ready for runtime validation.', target, enabledWhen(!busy && !!definitionId && hasAppliedMaterialization, busy ? 'busy' : !definitionId ? 'missing_definition' : 'missing_materialization')),
17843
- sharedRuleAction('open_timeline', 'Open timeline', 'Open safe timeline observability for this governed decision.', target, enabledWhen(!busy && !!definitionId && hasTimelineEvents, busy ? 'busy' : !definitionId ? 'missing_definition' : 'timeline_unavailable')),
17897
+ sharedRuleAction('open_definition', 'Preparar regra', 'Preparar ou abrir a regra governada para revisão.', target, enabledWhen(!busy && hasAuthoringTarget && !definitionId, busy ? 'busy' : definitionId ? 'definition_already_available' : !handoff ? 'missing_handoff' : 'missing_authoring_target')),
17898
+ sharedRuleAction('simulate', 'Simular impacto', 'Verificar o efeito da regra antes de publicar.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17899
+ sharedRuleAction('approve', 'Aprovar revisão', 'Aprovar a regra governada depois da conferência.', target, enabledWhen(!busy && !!definitionId && definitionStatus !== 'approved' && definitionStatus !== 'active', busy ? 'busy' : !definitionId ? 'missing_definition' : 'definition_already_available')),
17900
+ sharedRuleAction('publish', 'Publicar alteração', 'Publicar a decisão aprovada e atualizar as telas que dependem dela.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17901
+ sharedRuleAction('materialize', 'Ver telas afetadas', 'Ver quais telas serão atualizadas por essa decisão governada.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17902
+ sharedRuleAction('validate_enforcement', 'Validar aplicação', 'Conferir se a alteração publicada está pronta para uso.', target, enabledWhen(!busy && !!definitionId && hasAppliedMaterialization, busy ? 'busy' : !definitionId ? 'missing_definition' : 'missing_materialization')),
17903
+ sharedRuleAction('open_timeline', 'Ver histórico', 'Abrir o histórico seguro dessa decisão governada.', target, enabledWhen(!busy && !!definitionId && hasTimelineEvents, busy ? 'busy' : !definitionId ? 'missing_definition' : 'timeline_unavailable')),
17844
17904
  ];
17845
17905
  }
17846
17906
  function deriveProjectKnowledgeContinuationActions(input) {
@@ -17855,12 +17915,12 @@ function deriveProjectKnowledgeContinuationActions(input) {
17855
17915
  const hasTimelineEvents = (input.timeline?.events?.length ?? 0) > 0;
17856
17916
  const target = projectKnowledgeTarget(changeSet, candidate?.conceptKey ?? null);
17857
17917
  return [
17858
- projectKnowledgeAction('create_knowledge_change_set', 'Create change-set', 'Create a governed proposal from cited Project Knowledge.', target, enabledWhen(!busy && !!audit && !!candidate && !changeSet, busy ? 'busy' : !audit ? 'missing_project_knowledge_audit' : !candidate ? 'missing_project_knowledge_candidate' : 'change_set_already_available')),
17859
- projectKnowledgeAction('validate_knowledge_change_set', 'Validate change-set', 'Run deterministic validation before review.', target, enabledWhen(!busy && !!changeSet && validationStatus !== 'valid', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_already_valid')),
17860
- projectKnowledgeAction('approve', 'Approve', 'Approve the valid change-set explicitly.', target, enabledWhen(!busy && !!changeSet && validationValid && status !== 'approved' && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_required')),
17861
- projectKnowledgeAction('reject', 'Reject', 'Reject the proposed change-set without applying knowledge.', target, enabledWhen(!busy && !!changeSet && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'already_applied')),
17862
- projectKnowledgeAction('apply_knowledge_change_set', 'Apply change-set', 'Apply only after approval and valid persisted validation.', target, enabledWhen(!busy && !!changeSet && validationValid && status === 'approved', busy ? 'busy' : !changeSet ? 'missing_change_set' : !validationValid ? 'validation_required' : status === 'applied' ? 'already_applied' : 'approval_required')),
17863
- projectKnowledgeAction('open_timeline', 'Open timeline', 'Open safe Domain Knowledge timeline observability.', target, enabledWhen(!busy && !!changeSet && hasTimelineEvents, busy ? 'busy' : !changeSet ? 'missing_change_set' : 'timeline_unavailable')),
17918
+ projectKnowledgeAction('create_knowledge_change_set', 'Preparar revisão', 'Preparar uma proposta governada a partir do conhecimento citado.', target, enabledWhen(!busy && !!audit && !!candidate && !changeSet, busy ? 'busy' : !audit ? 'missing_project_knowledge_audit' : !candidate ? 'missing_project_knowledge_candidate' : 'change_set_already_available')),
17919
+ projectKnowledgeAction('validate_knowledge_change_set', 'Validar proposta', 'Conferir a proposta antes da revisão.', target, enabledWhen(!busy && !!changeSet && validationStatus !== 'valid', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_already_valid')),
17920
+ projectKnowledgeAction('approve', 'Aprovar revisão', 'Aprovar explicitamente a proposta validada.', target, enabledWhen(!busy && !!changeSet && validationValid && status !== 'approved' && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_required')),
17921
+ projectKnowledgeAction('reject', 'Rejeitar proposta', 'Rejeitar a proposta sem aplicar mudanças no conhecimento.', target, enabledWhen(!busy && !!changeSet && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'already_applied')),
17922
+ projectKnowledgeAction('apply_knowledge_change_set', 'Aplicar conhecimento', 'Aplicar somente depois da aprovação e da validação.', target, enabledWhen(!busy && !!changeSet && validationValid && status === 'approved', busy ? 'busy' : !changeSet ? 'missing_change_set' : !validationValid ? 'validation_required' : status === 'applied' ? 'already_applied' : 'approval_required')),
17923
+ projectKnowledgeAction('open_timeline', 'Ver histórico', 'Abrir o histórico seguro dessa revisão de conhecimento.', target, enabledWhen(!busy && !!changeSet && hasTimelineEvents, busy ? 'busy' : !changeSet ? 'missing_change_set' : 'timeline_unavailable')),
17864
17924
  ];
17865
17925
  }
17866
17926
  function selectProjectKnowledgeContinuationCandidate(audit) {
@@ -17914,16 +17974,19 @@ function projectKnowledgeTarget(changeSet, conceptKey) {
17914
17974
  };
17915
17975
  }
17916
17976
 
17977
+ const AGENTIC_AUTHORING_TURN_TERMINAL_TIMEOUT_MS = 270_000;
17917
17978
  const AGENTIC_PAGE_COMPOSITION_REQUEST_OUTPUT = 'agenticPageCompositionRequested';
17918
17979
  class DynamicPageBuilderComponent {
17919
17980
  dialog;
17920
17981
  settingsPanel;
17921
17982
  i18n = inject(PraxisI18nService);
17922
17983
  injector = inject(Injector);
17984
+ hostElement = inject((ElementRef));
17923
17985
  componentMetadata = inject(ComponentMetadataRegistry);
17924
17986
  agenticAuthoring = inject(PageBuilderAgenticAuthoringService);
17925
17987
  agenticTurnOrchestrator = inject(PraxisAssistantTurnOrchestratorService);
17926
17988
  assistantSessions = inject(PraxisAssistantSessionRegistryService);
17989
+ runtimeObservationRegistry = inject(PraxisRuntimeComponentObservationRegistryService, { optional: true });
17927
17990
  agenticAuthoringOptions = inject(PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, { optional: true });
17928
17991
  runtime;
17929
17992
  page;
@@ -17935,6 +17998,9 @@ class DynamicPageBuilderComponent {
17935
17998
  pageIdentity;
17936
17999
  componentInstanceId;
17937
18000
  pageEditorComponent = DynamicPageConfigEditorComponent;
18001
+ componentPaletteAllowedWidgetIds = null;
18002
+ componentPaletteAllowedWidgetTags = null;
18003
+ componentPaletteAllowedPresetIds = null;
17938
18004
  enableAgenticAuthoring = false;
17939
18005
  agenticAuthoringProvider;
17940
18006
  agenticAuthoringModel;
@@ -17958,6 +18024,7 @@ class DynamicPageBuilderComponent {
17958
18024
  savedPageDeleteRequested = new EventEmitter();
17959
18025
  currentPage = signal({ widgets: [] }, ...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
17960
18026
  hasPageWidgets = computed(() => (this.currentPage().widgets || []).length > 0, ...(ngDevMode ? [{ debugName: "hasPageWidgets" }] : /* istanbul ignore next */ []));
18027
+ premiumReadinessIssues = computed(() => this.evaluatePremiumReadiness(this.currentPage()).slice(0, 3), ...(ngDevMode ? [{ debugName: "premiumReadinessIssues" }] : /* istanbul ignore next */ []));
17961
18028
  connectionsViewerOpen = signal(false, ...(ngDevMode ? [{ debugName: "connectionsViewerOpen" }] : /* istanbul ignore next */ []));
17962
18029
  agenticAuthoringOpen = signal(false, ...(ngDevMode ? [{ debugName: "agenticAuthoringOpen" }] : /* istanbul ignore next */ []));
17963
18030
  agenticAuthoringPrompt = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringPrompt" }] : /* istanbul ignore next */ []));
@@ -18002,6 +18069,9 @@ class DynamicPageBuilderComponent {
18002
18069
  agenticComponentCapabilities;
18003
18070
  agenticComponentCapabilitiesPromise;
18004
18071
  agenticTurnController;
18072
+ agenticTurnCancel$ = new Subject();
18073
+ agenticTurnRunId = 0;
18074
+ agenticAuthoringTurnTerminalTimeoutMs = AGENTIC_AUTHORING_TURN_TERMINAL_TIMEOUT_MS;
18005
18075
  sharedRuleHandoffRevision = 0;
18006
18076
  agenticAuthoringPanelLayoutTouched = false;
18007
18077
  constructor(dialog, settingsPanel) {
@@ -18023,9 +18093,31 @@ class DynamicPageBuilderComponent {
18023
18093
  this.resetAgenticAuthoringSessionState();
18024
18094
  }
18025
18095
  }
18096
+ ngOnDestroy() {
18097
+ this.cancelActiveAgenticTurn();
18098
+ this.agenticTurnCancel$.complete();
18099
+ }
18026
18100
  showSettings() {
18027
18101
  return !!this.enableCustomization && !this.previewMode;
18028
18102
  }
18103
+ isPreviewMode() {
18104
+ return this.previewMode;
18105
+ }
18106
+ builderModeLabel() {
18107
+ if (this.previewMode) {
18108
+ return this.tx('builderMode.preview', 'Prévia');
18109
+ }
18110
+ if (this.showSettings() && this.connectionsViewerOpen()) {
18111
+ return this.tx('builderMode.connections', 'Conexões');
18112
+ }
18113
+ if (this.showSettings() && this.enableAgenticAuthoring && this.agenticAuthoringOpen()) {
18114
+ return this.tx('builderMode.ai', 'AI');
18115
+ }
18116
+ if (this.showSettings()) {
18117
+ return this.tx('builderMode.editing', 'Editing');
18118
+ }
18119
+ return this.tx('builderMode.presentation', 'Presentation');
18120
+ }
18029
18121
  onRuntimePageChange(next) {
18030
18122
  const cloned = this.clonePage(next);
18031
18123
  this.currentPage.set(cloned);
@@ -18085,10 +18177,21 @@ class DynamicPageBuilderComponent {
18085
18177
  toggleConnectionsViewer() {
18086
18178
  this.connectionsViewerOpen.update((current) => !current);
18087
18179
  }
18180
+ connectionsToggleLabel() {
18181
+ if (this.connectionsViewerOpen()) {
18182
+ return this.tx('connections.close', 'Close connections');
18183
+ }
18184
+ return this.tx('connections.toggle', 'Edit connections');
18185
+ }
18088
18186
  onAddComponent() {
18089
18187
  const ref = this.dialog.open(ComponentPaletteDialogComponent, {
18090
18188
  width: '720px',
18091
- data: { title: this.tx('connections.palette.insertComponent', 'Insert component') },
18189
+ data: {
18190
+ title: this.tx('connections.palette.insertComponent', 'Insert component'),
18191
+ allowedWidgetIds: this.componentPaletteAllowedWidgetIds || undefined,
18192
+ allowedWidgetTags: this.componentPaletteAllowedWidgetTags || undefined,
18193
+ allowedPresetIds: this.componentPaletteAllowedPresetIds || undefined,
18194
+ },
18092
18195
  });
18093
18196
  ref.afterClosed().subscribe((selection) => {
18094
18197
  if (selection)
@@ -18107,6 +18210,10 @@ class DynamicPageBuilderComponent {
18107
18210
  next.widgets = widgets;
18108
18211
  if (next.canvas) {
18109
18212
  const lastRow = Math.max(1, ...Object.values(next.canvas.items || {}).map((item) => (item.row + item.rowSpan) - 1));
18213
+ const canvasColumns = Math.max(1, next.canvas.columns || 1);
18214
+ const layoutHints = this.layoutHintsFor(type);
18215
+ const colSpan = Math.min(canvasColumns, Math.max(1, layoutHints?.recommendedCols ?? Math.min(4, canvasColumns)));
18216
+ const rowSpan = Math.max(1, layoutHints?.recommendedRows ?? 2);
18110
18217
  next.canvas = {
18111
18218
  ...next.canvas,
18112
18219
  items: {
@@ -18114,18 +18221,38 @@ class DynamicPageBuilderComponent {
18114
18221
  [key]: {
18115
18222
  col: 1,
18116
18223
  row: lastRow + 1,
18117
- colSpan: Math.min(4, Math.max(1, next.canvas.columns || 1)),
18118
- rowSpan: 2,
18224
+ colSpan,
18225
+ rowSpan,
18119
18226
  },
18120
18227
  },
18121
18228
  };
18122
18229
  }
18123
18230
  this.currentPage.set(next);
18231
+ this.selectInsertedWidget(key, widgets.length);
18124
18232
  this.pageChange.emit(this.clonePage(next));
18125
18233
  }
18234
+ layoutHintsFor(componentId) {
18235
+ const metadataHints = this.componentMetadata.get(componentId)?.layoutHints;
18236
+ if (metadataHints) {
18237
+ return metadataHints;
18238
+ }
18239
+ switch (componentId) {
18240
+ case 'praxis-table':
18241
+ return { recommendedCols: 8, recommendedRows: 6 };
18242
+ case 'praxis-filter':
18243
+ return { recommendedCols: 12, recommendedRows: 3 };
18244
+ case 'praxis-chart':
18245
+ case 'praxis-list':
18246
+ case 'praxis-crud':
18247
+ return { recommendedCols: 8, recommendedRows: 5 };
18248
+ default:
18249
+ return undefined;
18250
+ }
18251
+ }
18126
18252
  openPageSettings() {
18127
18253
  if (!this.pageEditorComponent)
18128
18254
  return;
18255
+ this.connectionsViewerOpen.set(false);
18129
18256
  this.runtime?.openPageSettings();
18130
18257
  }
18131
18258
  saveCurrentPage() {
@@ -18142,6 +18269,181 @@ class DynamicPageBuilderComponent {
18142
18269
  canSaveCurrentPage() {
18143
18270
  return this.hasPageWidgets() && !this.hasBlockingAgenticReview();
18144
18271
  }
18272
+ evaluatePremiumReadiness(page) {
18273
+ const widgets = page.widgets || [];
18274
+ if (!widgets.length) {
18275
+ return [];
18276
+ }
18277
+ const issues = [];
18278
+ const themePreset = (page.themePreset || '').trim();
18279
+ const hasKnownThemePreset = !!themePreset && Object.prototype.hasOwnProperty.call(BUILTIN_PAGE_THEME_PRESETS, themePreset);
18280
+ const isDashboard = this.isPremiumReadinessCandidate(page);
18281
+ if (!isDashboard) {
18282
+ return [];
18283
+ }
18284
+ if (!themePreset) {
18285
+ issues.push({
18286
+ id: 'theme-missing',
18287
+ severity: 'warning',
18288
+ title: this.tx('premiumReadiness.themeMissing.title', 'Defina um tema executivo'),
18289
+ description: this.tx('premiumReadiness.themeMissing.description', 'Dashboards corporativos precisam de preset visual para densidade, shell e tokens consistentes.'),
18290
+ action: {
18291
+ kind: 'open-page-settings',
18292
+ label: this.tx('premiumReadiness.actions.openPageSettings', 'Abrir configurações da página'),
18293
+ },
18294
+ });
18295
+ }
18296
+ else if (!hasKnownThemePreset) {
18297
+ issues.push({
18298
+ id: 'theme-unknown',
18299
+ severity: 'error',
18300
+ title: this.tx('premiumReadiness.themeUnknown.title', 'Tema não reconhecido'),
18301
+ description: this.tx('premiumReadiness.themeUnknown.description', 'O preset informado não existe no catálogo canônico e pode cair em aparência genérica.'),
18302
+ action: {
18303
+ kind: 'open-page-settings',
18304
+ label: this.tx('premiumReadiness.actions.reviewTheme', 'Revisar tema'),
18305
+ },
18306
+ });
18307
+ }
18308
+ if (isDashboard && page.canvas && !page.deviceLayouts?.mobile?.canvas) {
18309
+ issues.push({
18310
+ id: 'mobile-layout-missing',
18311
+ severity: 'warning',
18312
+ title: this.tx('premiumReadiness.mobileMissing.title', 'Inclua layout mobile'),
18313
+ description: this.tx('premiumReadiness.mobileMissing.description', 'Uma página premium precisa preservar hierarquia e leitura em telas menores.'),
18314
+ action: {
18315
+ kind: 'open-page-settings',
18316
+ label: this.tx('premiumReadiness.actions.openDeviceLayouts', 'Abrir layouts'),
18317
+ },
18318
+ });
18319
+ }
18320
+ if (this.hasDisconnectedOperationalWidgets(page)) {
18321
+ issues.push({
18322
+ id: 'widgets-disconnected',
18323
+ severity: 'warning',
18324
+ title: this.tx('premiumReadiness.disconnected.title', 'Conecte filtros, gráficos e filas'),
18325
+ description: this.tx('premiumReadiness.disconnected.description', 'A composição parece visualmente rica, mas ainda não mostra causa e efeito entre widgets.'),
18326
+ action: {
18327
+ kind: 'open-connections',
18328
+ label: this.tx('premiumReadiness.actions.openConnections', 'Abrir conexões'),
18329
+ },
18330
+ });
18331
+ }
18332
+ const localAnalyticWidget = widgets.find((widget) => this.usesLocalAnalyticData(widget));
18333
+ if (localAnalyticWidget) {
18334
+ issues.push({
18335
+ id: 'local-data-source',
18336
+ severity: 'info',
18337
+ title: this.tx('premiumReadiness.localData.title', 'Troque dados locais por fonte governada'),
18338
+ description: this.tx('premiumReadiness.localData.description', 'Dados locais ajudam a prototipar, mas produção deve apontar para recurso, endpoint ou estado governado.'),
18339
+ action: {
18340
+ kind: 'open-widget-config',
18341
+ label: this.tx('premiumReadiness.actions.openWidgetConfig', 'Abrir widget'),
18342
+ widgetKey: localAnalyticWidget.key,
18343
+ },
18344
+ });
18345
+ }
18346
+ const latePrimaryChartKey = this.latePrimaryChartKey(page);
18347
+ if (latePrimaryChartKey) {
18348
+ issues.push({
18349
+ id: 'late-primary-chart',
18350
+ severity: 'info',
18351
+ title: this.tx('premiumReadiness.chartHierarchy.title', 'Suba o gráfico principal'),
18352
+ description: this.tx('premiumReadiness.chartHierarchy.description', 'O primeiro gráfico deveria aparecer cedo o bastante para orientar a primeira dobra.'),
18353
+ action: {
18354
+ kind: 'focus-widget',
18355
+ label: this.tx('premiumReadiness.actions.focusChart', 'Focar gráfico'),
18356
+ widgetKey: latePrimaryChartKey,
18357
+ },
18358
+ });
18359
+ }
18360
+ return issues;
18361
+ }
18362
+ runPremiumReadinessAction(issue) {
18363
+ const action = issue.action;
18364
+ if (!action)
18365
+ return;
18366
+ if (this.previewMode) {
18367
+ this.previewMode = false;
18368
+ }
18369
+ switch (action.kind) {
18370
+ case 'open-page-settings':
18371
+ this.openPageSettings();
18372
+ return;
18373
+ case 'open-connections':
18374
+ this.connectionsViewerOpen.set(true);
18375
+ return;
18376
+ case 'open-widget-config':
18377
+ if (action.widgetKey) {
18378
+ this.openWidgetConfiguration(action.widgetKey);
18379
+ }
18380
+ return;
18381
+ case 'focus-widget':
18382
+ if (action.widgetKey) {
18383
+ this.connectionsViewerOpen.set(false);
18384
+ this.focusCanvasWidget(action.widgetKey);
18385
+ }
18386
+ return;
18387
+ }
18388
+ }
18389
+ isPremiumReadinessCandidate(page) {
18390
+ const widgets = page.widgets || [];
18391
+ if (widgets.length >= 4) {
18392
+ return true;
18393
+ }
18394
+ const analyticWidgets = widgets.filter((widget) => this.isAnalyticWidget(widget.definition?.id));
18395
+ if (analyticWidgets.length >= 2) {
18396
+ return true;
18397
+ }
18398
+ const hasFilter = widgets.some((widget) => widget.definition?.id === 'praxis-filter');
18399
+ if (hasFilter && analyticWidgets.length > 0) {
18400
+ return true;
18401
+ }
18402
+ return (page.composition?.links || []).length > 0 && analyticWidgets.length > 0;
18403
+ }
18404
+ hasDisconnectedOperationalWidgets(page) {
18405
+ const widgets = page.widgets || [];
18406
+ const hasFilter = widgets.some((widget) => widget.definition?.id === 'praxis-filter');
18407
+ const hasConsumer = widgets.some((widget) => {
18408
+ const id = widget.definition?.id;
18409
+ return id === 'praxis-chart' || id === 'praxis-list' || id === 'praxis-table';
18410
+ });
18411
+ if (!hasFilter || !hasConsumer) {
18412
+ return false;
18413
+ }
18414
+ return !(page.composition?.links || []).length;
18415
+ }
18416
+ latePrimaryChartKey(page) {
18417
+ const chartKeys = (page.widgets || [])
18418
+ .filter((widget) => widget.definition?.id === 'praxis-chart')
18419
+ .map((widget) => widget.key)
18420
+ .filter(Boolean);
18421
+ if (!chartKeys.length || !page.canvas?.items) {
18422
+ return null;
18423
+ }
18424
+ const firstChart = chartKeys
18425
+ .map((key) => ({ key, row: page.canvas?.items?.[key]?.row }))
18426
+ .filter((item) => typeof item.row === 'number')
18427
+ .sort((left, right) => left.row - right.row)[0];
18428
+ return firstChart && firstChart.row > 8 ? firstChart.key : null;
18429
+ }
18430
+ usesLocalAnalyticData(widget) {
18431
+ if (!this.isAnalyticWidget(widget.definition?.id)) {
18432
+ return false;
18433
+ }
18434
+ const config = widget.definition?.inputs?.['config'];
18435
+ const configRecord = this.toRecord(config);
18436
+ if (!configRecord) {
18437
+ return false;
18438
+ }
18439
+ const dataSource = this.toRecord(configRecord['dataSource']);
18440
+ return dataSource?.['kind'] === 'local';
18441
+ }
18442
+ isAnalyticWidget(componentId) {
18443
+ return componentId === 'praxis-chart'
18444
+ || componentId === 'praxis-list'
18445
+ || componentId === 'praxis-table';
18446
+ }
18145
18447
  applyConfigFromAdapter(config) {
18146
18448
  if (!config.page)
18147
18449
  return;
@@ -18188,9 +18490,9 @@ class DynamicPageBuilderComponent {
18188
18490
  this.syncAgenticAuthoringSession('active');
18189
18491
  }
18190
18492
  minimizeAgenticAuthoring() {
18191
- this.agenticAuthoringOpen.set(false);
18192
18493
  this.agenticAuthoringError.set('');
18193
18494
  this.syncAgenticAuthoringSession('minimized');
18495
+ this.agenticAuthoringOpen.set(false);
18194
18496
  }
18195
18497
  onAgenticAuthoringLayoutChange(layout) {
18196
18498
  this.agenticAuthoringPanelLayoutTouched = true;
@@ -18214,90 +18516,90 @@ class DynamicPageBuilderComponent {
18214
18516
  }
18215
18517
  agenticAuthoringToggleLabel() {
18216
18518
  if (this.agenticAuthoringOpen()) {
18217
- return this.tx('agentic.toggle.minimize', 'Minimize Praxis copilot');
18519
+ return this.tx('agentic.toggle.minimize', 'Minimizar copiloto Praxis');
18218
18520
  }
18219
18521
  if (this.agenticAuthoringMinimized()) {
18220
- return this.tx('agentic.dock.openTooltip', 'Reopen Praxis copilot');
18522
+ return this.tx('agentic.dock.openTooltip', 'Reabrir copiloto Praxis');
18221
18523
  }
18222
- return this.tx('agentic.toggle', 'Create with AI');
18524
+ return this.tx('agentic.toggle', 'Criar com IA');
18223
18525
  }
18224
18526
  agenticAuthoringHeaderTitle() {
18225
18527
  if (this.agenticAuthoringSharedRuleHandoffState()) {
18226
- return this.tx('agentic.header.title.governed', 'Praxis governed copilot');
18528
+ return this.tx('agentic.header.title.governed', 'Copiloto governado Praxis');
18227
18529
  }
18228
18530
  if (this.agenticAuthoringPreviewResult()?.valid) {
18229
- return this.tx('agentic.header.title.review', 'Praxis review copilot');
18531
+ return this.tx('agentic.header.title.review', 'Copiloto de revisão Praxis');
18230
18532
  }
18231
18533
  if (this.resolveSelectedWidgetKey()) {
18232
- return this.tx('agentic.header.title.widget', 'Praxis widget copilot');
18534
+ return this.tx('agentic.header.title.widget', 'Copiloto de componente Praxis');
18233
18535
  }
18234
- return this.tx('agentic.header.title.page', 'Praxis page decision copilot');
18536
+ return this.tx('agentic.header.title.page', 'Copiloto de página Praxis');
18235
18537
  }
18236
18538
  agenticAuthoringHeaderSubtitle() {
18237
18539
  const selectedWidgetLabel = this.resolveSelectedWidgetLabel();
18238
18540
  if (this.agenticAuthoringSharedRuleHandoffState()) {
18239
- return this.tx('agentic.header.subtitle.governed', 'Continue the governed semantic-decision flow.');
18541
+ return this.tx('agentic.header.subtitle.governed', 'Continue a revisão da regra antes de criar a tela.');
18240
18542
  }
18241
18543
  if (this.agenticAuthoringPreviewResult()?.valid) {
18242
18544
  if (!this.agenticAuthoringCanApply()) {
18243
- return this.tx('agentic.header.subtitle.reviewBlocked', 'Preview ready for governed review.');
18545
+ return this.tx('agentic.header.subtitle.reviewBlocked', 'Prévia pronta, com pontos para revisar.');
18244
18546
  }
18245
- return this.tx('agentic.header.subtitle.review', 'Preview ready for review and persistence.');
18547
+ return this.tx('agentic.header.subtitle.review', 'Prévia pronta para revisar e salvar.');
18246
18548
  }
18247
18549
  if (selectedWidgetLabel) {
18248
- return this.tx('agentic.header.subtitle.widget', 'Focused on {target}.')
18550
+ return this.tx('agentic.header.subtitle.widget', 'Foco em {target}.')
18249
18551
  .replace('{target}', selectedWidgetLabel);
18250
18552
  }
18251
18553
  const routePath = this.pageIdentity?.routePath?.trim();
18252
18554
  if (routePath) {
18253
- return this.tx('agentic.header.subtitle.route', 'Authoring page route {route}.')
18555
+ return this.tx('agentic.header.subtitle.route', 'Criando ou ajustando a página {route}.')
18254
18556
  .replace('{route}', routePath);
18255
18557
  }
18256
- return this.tx('agentic.header.subtitle.page', 'Turn intent into layout, widgets, and governed materializations.');
18558
+ return this.tx('agentic.header.subtitle.page', 'Transforme uma necessidade do domínio em tabela, formulário ou painel.');
18257
18559
  }
18258
18560
  agenticAuthoringHeaderModeLabel() {
18259
18561
  if (this.agenticAuthoringSharedRuleHandoffState()) {
18260
- return this.tx('agentic.header.mode.governed', 'Governed');
18562
+ return this.tx('agentic.header.mode.governed', 'Governado');
18261
18563
  }
18262
18564
  if (this.resolveSelectedWidgetKey()) {
18263
18565
  return this.tx('agentic.header.mode.widget', 'Widget');
18264
18566
  }
18265
- return this.tx('agentic.header.mode.page', 'Page');
18567
+ return this.tx('agentic.header.mode.page', 'Página');
18266
18568
  }
18267
18569
  agenticAuthoringShellLabels() {
18268
18570
  return {
18269
18571
  title: this.agenticAuthoringHeaderTitle(),
18270
18572
  subtitle: this.agenticAuthoringHeaderSubtitle(),
18271
- close: this.tx('agentic.minimize', 'Minimize'),
18272
- prompt: this.tx('agentic.promptLabel', 'Message'),
18273
- promptPlaceholder: this.tx('agentic.promptPlaceholder', 'Describe the page, dashboard, form or change you need.'),
18573
+ close: this.tx('agentic.minimize', 'Minimizar'),
18574
+ prompt: this.tx('agentic.promptLabel', 'Mensagem'),
18575
+ promptPlaceholder: this.tx('agentic.promptPlaceholder', 'Descreva a página, dashboard, formulário ou alteração que você precisa.'),
18274
18576
  emptyConversation: this.agenticAuthoringEmptyConversationMessage(),
18275
- submit: this.tx('agentic.preview', 'Generate preview'),
18276
- apply: this.tx('agentic.persist', 'Save'),
18277
- conversationAria: this.tx('agentic.conversationAria', 'AI conversation'),
18278
- quickRepliesAria: this.tx('agentic.quickRepliesAria', 'Quick replies'),
18279
- dragHandleAria: this.tx('agentic.dragHandleAria', 'Move AI assistant'),
18280
- resizeHandleAria: this.tx('agentic.resizeHandleAria', 'Resize AI assistant'),
18281
- contextAria: this.tx('agentic.contextAria', 'Active context'),
18282
- attachmentsAria: this.tx('agentic.attachmentsAria', 'Attached context'),
18283
- attach: this.tx('agentic.attach', 'Attach'),
18284
- removeAttachment: this.tx('agentic.removeAttachment', 'Remove attachment'),
18285
- editMessage: this.tx('agentic.editMessage', 'Edit'),
18286
- resendMessage: this.tx('agentic.resendMessage', 'Resend'),
18577
+ submit: this.tx('agentic.submit', 'Enviar pedido'),
18578
+ apply: this.tx('agentic.persist', 'Salvar'),
18579
+ conversationAria: this.tx('agentic.conversationAria', 'Conversa com IA'),
18580
+ quickRepliesAria: this.tx('agentic.quickRepliesAria', 'Respostas rápidas'),
18581
+ dragHandleAria: this.tx('agentic.dragHandleAria', 'Mover assistente de IA'),
18582
+ resizeHandleAria: this.tx('agentic.resizeHandleAria', 'Redimensionar assistente de IA'),
18583
+ contextAria: this.tx('agentic.contextAria', 'Contexto ativo'),
18584
+ attachmentsAria: this.tx('agentic.attachmentsAria', 'Contexto anexado'),
18585
+ attach: this.tx('agentic.attach', 'Anexar'),
18586
+ removeAttachment: this.tx('agentic.removeAttachment', 'Remover anexo'),
18587
+ editMessage: this.tx('agentic.editMessage', 'Editar'),
18588
+ resendMessage: this.tx('agentic.resendMessage', 'Reenviar'),
18287
18589
  modeAgenticAuthoring: this.agenticAuthoringHeaderModeLabel(),
18288
- modeConfig: this.tx('agentic.mode.config', 'Configuration'),
18590
+ modeConfig: this.tx('agentic.mode.config', 'Configuração'),
18289
18591
  modeChat: this.tx('agentic.mode.chat', 'Chat'),
18290
- modeDiagnostic: this.tx('agentic.mode.diagnostic', 'Diagnostic'),
18291
- modeReview: this.tx('agentic.mode.review', 'Review'),
18292
- modeInlineHelp: this.tx('agentic.mode.inlineHelp', 'Help'),
18293
- stateIdle: this.tx('agentic.state.idle', 'Ready'),
18294
- stateListening: this.tx('agentic.state.listening', 'Ready'),
18295
- stateProcessing: this.tx('agentic.state.processing', 'Processing'),
18296
- stateClarification: this.tx('agentic.state.clarification', 'Waiting for input'),
18297
- stateReview: this.tx('agentic.state.review', 'Review'),
18298
- stateApplying: this.tx('agentic.state.applying', 'Applying'),
18299
- stateSuccess: this.tx('agentic.state.success', 'Done'),
18300
- stateError: this.tx('agentic.state.error', 'Error'),
18592
+ modeDiagnostic: this.tx('agentic.mode.diagnostic', 'Diagnóstico'),
18593
+ modeReview: this.tx('agentic.mode.review', 'Revisão'),
18594
+ modeInlineHelp: this.tx('agentic.mode.inlineHelp', 'Ajuda'),
18595
+ stateIdle: this.tx('agentic.state.idle', 'Pronto'),
18596
+ stateListening: this.tx('agentic.state.listening', 'Pronto'),
18597
+ stateProcessing: this.tx('agentic.state.processing', 'Processando'),
18598
+ stateClarification: this.tx('agentic.state.clarification', 'Aguardando resposta'),
18599
+ stateReview: this.tx('agentic.state.review', 'Revisão'),
18600
+ stateApplying: this.tx('agentic.state.applying', 'Aplicando'),
18601
+ stateSuccess: this.tx('agentic.state.success', 'Concluído'),
18602
+ stateError: this.tx('agentic.state.error', 'Erro'),
18301
18603
  };
18302
18604
  }
18303
18605
  agenticAuthoringEmptyConversationMessage() {
@@ -18306,9 +18608,9 @@ class DynamicPageBuilderComponent {
18306
18608
  return authoredOpening;
18307
18609
  }
18308
18610
  if (this.isAgenticAuthoringPageBlank()) {
18309
- return this.tx('agentic.emptyConversation.blankGeneric', 'This host page is still blank. Tell me what decision or activity this app needs to support. I can suggest a dashboard, table, form, or review flow, then turn it into a governed preview for you to review before anything changes.');
18611
+ return this.tx('agentic.emptyConversation.blankGeneric', 'Esta tela ainda está vazia. Diga qual atividade do domínio ela precisa apoiar. Posso sugerir um painel, tabela ou formulário e montar uma prévia para você revisar antes de salvar.');
18310
18612
  }
18311
- return this.tx('agentic.emptyConversation.existingPage', 'Tell me what you want to improve here. I can read the current layout, widgets, route, and governed context, then prepare a preview for you to review before anything changes.');
18613
+ return this.tx('agentic.emptyConversation.existingPage', 'Diga o que você quer melhorar nesta tela. Eu leio o que existe e preparo uma prévia para você revisar antes de salvar.');
18312
18614
  }
18313
18615
  resolveAgenticAuthoredOpeningMessage() {
18314
18616
  const hints = this.toRecord(this.agenticAuthoringContextHints);
@@ -18337,7 +18639,7 @@ class DynamicPageBuilderComponent {
18337
18639
  return !!this.agenticAuthoringPreviewResult()?.valid && !this.agenticAuthoringCanApply();
18338
18640
  }
18339
18641
  agenticAuthoringSubmitAction() {
18340
- const label = this.tx('agentic.preview', 'Generate preview');
18642
+ const label = this.tx('agentic.submit', 'Enviar pedido');
18341
18643
  return {
18342
18644
  id: 'submit',
18343
18645
  kind: 'submit-prompt',
@@ -18365,14 +18667,14 @@ class DynamicPageBuilderComponent {
18365
18667
  agenticAuthoringDockBadge() {
18366
18668
  const state = this.agenticAuthoringShellState();
18367
18669
  if (state === 'error')
18368
- return this.tx('agentic.dock.badgeError', 'Attention');
18670
+ return this.tx('agentic.dock.badgeError', 'Atenção');
18369
18671
  if (state === 'processing' || state === 'applying')
18370
- return this.tx('agentic.dock.badgeWorking', 'Working');
18672
+ return this.tx('agentic.dock.badgeWorking', 'Trabalhando');
18371
18673
  if (state === 'review')
18372
- return this.tx('agentic.dock.badgeReview', 'Review');
18674
+ return this.tx('agentic.dock.badgeReview', 'Revisão');
18373
18675
  if (state === 'clarification')
18374
- return this.tx('agentic.dock.badgeGoverned', 'Governed');
18375
- return this.tx('agentic.dock.badgeReady', 'Ready');
18676
+ return this.tx('agentic.dock.badgeGoverned', 'Governado');
18677
+ return this.tx('agentic.dock.badgeReady', 'Pronto');
18376
18678
  }
18377
18679
  agenticAuthoringDockSummary() {
18378
18680
  const status = this.agenticAuthoringStatus().trim();
@@ -18388,12 +18690,12 @@ class DynamicPageBuilderComponent {
18388
18690
  return this.truncateAgenticDockText(lastMessage.text);
18389
18691
  }
18390
18692
  if (this.agenticAuthoringPreviewResult()?.valid) {
18391
- return this.tx('agentic.dock.summaryReview', 'Preview ready. Reopen to review or save.');
18693
+ return this.tx('agentic.dock.summaryReview', 'Prévia pronta. Reabra para revisar ou salvar.');
18392
18694
  }
18393
18695
  if (this.agenticAuthoringSharedRuleHandoffState()) {
18394
- return this.tx('agentic.dock.summaryGoverned', 'Governed handoff preserved. Continue the semantic decision flow.');
18696
+ return this.tx('agentic.dock.summaryGoverned', 'Revisão preservada. Continue de onde parou.');
18395
18697
  }
18396
- return this.tx('agentic.dock.summaryIdle', 'Conversation preserved. Continue where you stopped.');
18698
+ return this.tx('agentic.dock.summaryIdle', 'Conversa preservada. Continue de onde parou.');
18397
18699
  }
18398
18700
  agenticAuthoringShellState() {
18399
18701
  if (this.agenticAuthoringBusy())
@@ -18901,6 +19203,7 @@ class DynamicPageBuilderComponent {
18901
19203
  const prompt = this.agenticAuthoringPrompt().trim();
18902
19204
  if (!prompt || this.agenticAuthoringBusy())
18903
19205
  return;
19206
+ const turnRunId = this.beginAgenticTurn();
18904
19207
  this.agenticAuthoringBusy.set(true);
18905
19208
  this.agenticAuthoringError.set('');
18906
19209
  this.agenticAuthoringPreviewResult.set(null);
@@ -18908,37 +19211,43 @@ class DynamicPageBuilderComponent {
18908
19211
  this.agenticAuthoringSharedRuleHandoffState.set(null);
18909
19212
  this.clearSharedRuleCockpitState();
18910
19213
  this.clearProjectKnowledgeCockpitState();
18911
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19214
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
18912
19215
  try {
18913
19216
  const controller = this.ensureAgenticTurnController();
18914
19217
  const editingMessageId = this.agenticAuthoringEditingMessageId();
18915
19218
  await this.consumeAgenticTurn(editingMessageId
18916
19219
  ? controller.submitEditedMessage(editingMessageId, prompt)
18917
- : controller.submitPrompt(prompt));
19220
+ : controller.submitPrompt(prompt), turnRunId);
18918
19221
  this.agenticAuthoringEditingMessageId.set(null);
18919
19222
  this.agenticAuthoringPrompt.set('');
18920
19223
  }
18921
19224
  catch (error) {
19225
+ if (!this.isCurrentAgenticTurn(turnRunId))
19226
+ return;
18922
19227
  this.agenticAuthoringStatus.set('');
18923
19228
  const message = this.describeAgenticError(error);
18924
19229
  this.agenticAuthoringError.set(message);
18925
19230
  this.appendAgenticMessage('error', message);
18926
19231
  }
18927
19232
  finally {
18928
- this.agenticAuthoringBusy.set(false);
19233
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19234
+ this.agenticAuthoringBusy.set(false);
19235
+ }
18929
19236
  }
18930
19237
  }
18931
19238
  async submitAgenticQuickReply(reply) {
18932
19239
  const replyKind = (reply.kind || 'suggestion').trim().toLowerCase();
18933
19240
  if (replyKind === 'cancel') {
19241
+ this.cancelActiveAgenticTurn();
19242
+ this.agenticAuthoringBusy.set(false);
18934
19243
  this.agenticAuthoringEditingMessageId.set(null);
18935
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().cancel());
19244
+ await this.applyAgenticTurnState(await firstValueFrom(this.ensureAgenticTurnController().cancel()));
18936
19245
  return;
18937
19246
  }
18938
19247
  if (replyKind === 'revise') {
18939
19248
  this.agenticAuthoringEditingMessageId.set(null);
18940
19249
  this.agenticAuthoringQuickReplies.set([]);
18941
- this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Refine your prompt and preview again.'));
19250
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Ajuste o pedido e crie uma nova prévia.'));
18942
19251
  return;
18943
19252
  }
18944
19253
  this.agenticAuthoringEditingMessageId.set(null);
@@ -18949,6 +19258,7 @@ class DynamicPageBuilderComponent {
18949
19258
  return;
18950
19259
  }
18951
19260
  this.agenticAuthoringPrompt.set(visiblePrompt);
19261
+ const turnRunId = this.beginAgenticTurn();
18952
19262
  this.agenticAuthoringQuickReplies.set([]);
18953
19263
  this.agenticAuthoringBusy.set(true);
18954
19264
  this.agenticAuthoringError.set('');
@@ -18957,7 +19267,7 @@ class DynamicPageBuilderComponent {
18957
19267
  this.agenticAuthoringSharedRuleHandoffState.set(null);
18958
19268
  this.clearSharedRuleCockpitState();
18959
19269
  this.clearProjectKnowledgeCockpitState();
18960
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19270
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
18961
19271
  try {
18962
19272
  const controller = this.ensureAgenticTurnController();
18963
19273
  const actionKind = controller.snapshot().state === 'clarification'
@@ -18970,17 +19280,21 @@ class DynamicPageBuilderComponent {
18970
19280
  value: reply.prompt,
18971
19281
  displayPrompt: visiblePrompt,
18972
19282
  contextHints,
18973
- }));
19283
+ }), turnRunId);
18974
19284
  this.agenticAuthoringPrompt.set('');
18975
19285
  }
18976
19286
  catch (error) {
19287
+ if (!this.isCurrentAgenticTurn(turnRunId))
19288
+ return;
18977
19289
  this.agenticAuthoringStatus.set('');
18978
19290
  const message = this.describeAgenticError(error);
18979
19291
  this.agenticAuthoringError.set(message);
18980
19292
  this.appendAgenticMessage('error', message);
18981
19293
  }
18982
19294
  finally {
18983
- this.agenticAuthoringBusy.set(false);
19295
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19296
+ this.agenticAuthoringBusy.set(false);
19297
+ }
18984
19298
  }
18985
19299
  }
18986
19300
  agenticQuickReplyVisiblePrompt(reply, contextHints) {
@@ -19174,54 +19488,64 @@ class DynamicPageBuilderComponent {
19174
19488
  return;
19175
19489
  this.agenticAuthoringEditingMessageId.set(message.id);
19176
19490
  this.agenticAuthoringPrompt.set(message.text);
19177
- this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Refine your prompt and preview again.'));
19491
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Ajuste o pedido e crie uma nova prévia.'));
19178
19492
  }
19179
19493
  async resendAgenticMessage(message) {
19180
19494
  if (message.role !== 'user' || this.agenticAuthoringBusy())
19181
19495
  return;
19496
+ const turnRunId = this.beginAgenticTurn();
19182
19497
  this.agenticAuthoringEditingMessageId.set(null);
19183
19498
  this.agenticAuthoringBusy.set(true);
19184
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19499
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
19185
19500
  this.agenticAuthoringError.set('');
19186
19501
  this.agenticAuthoringPreviewResult.set(null);
19187
19502
  this.agenticAuthoringCanApply.set(false);
19188
19503
  this.clearProjectKnowledgeCockpitState();
19189
19504
  try {
19190
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().resendMessage(message.id));
19505
+ await this.consumeAgenticTurn(this.ensureAgenticTurnController().resendMessage(message.id), turnRunId);
19191
19506
  }
19192
19507
  catch (error) {
19508
+ if (!this.isCurrentAgenticTurn(turnRunId))
19509
+ return;
19193
19510
  this.agenticAuthoringStatus.set('');
19194
19511
  const errorMessage = this.describeAgenticError(error);
19195
19512
  this.agenticAuthoringError.set(errorMessage);
19196
19513
  this.appendAgenticMessage('error', errorMessage);
19197
19514
  }
19198
19515
  finally {
19199
- this.agenticAuthoringBusy.set(false);
19516
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19517
+ this.agenticAuthoringBusy.set(false);
19518
+ }
19200
19519
  }
19201
19520
  }
19202
19521
  async retryAgenticAuthoring() {
19203
19522
  if (this.agenticAuthoringBusy())
19204
19523
  return;
19524
+ const turnRunId = this.beginAgenticTurn();
19205
19525
  this.agenticAuthoringEditingMessageId.set(null);
19206
19526
  this.agenticAuthoringBusy.set(true);
19207
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19527
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
19208
19528
  this.agenticAuthoringError.set('');
19209
19529
  try {
19210
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().retry());
19530
+ await this.consumeAgenticTurn(this.ensureAgenticTurnController().retry(), turnRunId);
19211
19531
  }
19212
19532
  catch (error) {
19533
+ if (!this.isCurrentAgenticTurn(turnRunId))
19534
+ return;
19213
19535
  this.agenticAuthoringStatus.set('');
19214
19536
  const errorMessage = this.describeAgenticError(error);
19215
19537
  this.agenticAuthoringError.set(errorMessage);
19216
19538
  this.appendAgenticMessage('error', errorMessage);
19217
19539
  }
19218
19540
  finally {
19219
- this.agenticAuthoringBusy.set(false);
19541
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19542
+ this.agenticAuthoringBusy.set(false);
19543
+ }
19220
19544
  }
19221
19545
  }
19222
19546
  async cancelAgenticAuthoring() {
19223
- if (this.agenticAuthoringBusy())
19224
- return;
19547
+ this.cancelActiveAgenticTurn();
19548
+ this.agenticAuthoringBusy.set(false);
19225
19549
  this.agenticAuthoringEditingMessageId.set(null);
19226
19550
  this.agenticAuthoringPrompt.set('');
19227
19551
  this.agenticAuthoringPreviewResult.set(null);
@@ -19230,7 +19554,7 @@ class DynamicPageBuilderComponent {
19230
19554
  this.agenticAuthoringSharedRuleHandoffState.set(null);
19231
19555
  this.clearSharedRuleCockpitState();
19232
19556
  this.clearProjectKnowledgeCockpitState();
19233
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().cancel());
19557
+ await this.applyAgenticTurnState(await firstValueFrom(this.ensureAgenticTurnController().cancel()));
19234
19558
  }
19235
19559
  async persistAgenticAuthoring() {
19236
19560
  const preview = this.agenticAuthoringPreviewResult();
@@ -19243,7 +19567,7 @@ class DynamicPageBuilderComponent {
19243
19567
  }
19244
19568
  this.agenticAuthoringBusy.set(true);
19245
19569
  this.agenticAuthoringError.set('');
19246
- this.agenticAuthoringStatus.set(this.tx('agentic.status.saving', 'Saving page...'));
19570
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.saving', 'Salvando tela...'));
19247
19571
  try {
19248
19572
  const compiledFormPatch = this.resolvePreviewCompiledFormPatch(preview);
19249
19573
  const result = await firstValueFrom(this.agenticAuthoring.applyPage({
@@ -19263,7 +19587,7 @@ class DynamicPageBuilderComponent {
19263
19587
  this.agenticAuthoringCanApply.set(false);
19264
19588
  this.agenticAuthoringQuickReplies.set([]);
19265
19589
  this.agenticAuthoringPrompt.set('');
19266
- this.agenticAuthoringStatus.set(this.tx('agentic.status.saved', 'Page saved.'));
19590
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.saved', 'Tela salva.'));
19267
19591
  this.syncAgenticAuthoringSession();
19268
19592
  }
19269
19593
  catch (error) {
@@ -19280,7 +19604,7 @@ class DynamicPageBuilderComponent {
19280
19604
  return null;
19281
19605
  if (handoff.ruleDefinitionId?.trim()) {
19282
19606
  this.sharedRuleCockpitError.set('');
19283
- this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.definitionReady', 'Governed definition is ready for simulation and review.'));
19607
+ this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.definitionReady', 'Definição governada pronta para simulação e revisão.'));
19284
19608
  await this.refreshSharedRuleTimeline();
19285
19609
  return this.sharedRuleCockpitDefinition();
19286
19610
  }
@@ -19415,8 +19739,8 @@ class DynamicPageBuilderComponent {
19415
19739
  const enforcement = this.summarizeSharedRuleEnforcement(materializations);
19416
19740
  this.sharedRuleCockpitEnforcement.set(enforcement);
19417
19741
  this.appendAgenticMessage('assistant', enforcement.status === 'ready'
19418
- ? this.tx('agentic.sharedRuleCockpit.enforcementReady', 'Runtime enforcement validation is ready: applied materializations are available for consumer runtimes.')
19419
- : this.tx('agentic.sharedRuleCockpit.enforcementWaiting', 'Runtime enforcement is still waiting for applied materializations. Publish or review materialization status before validating a consumer runtime.'));
19742
+ ? this.tx('agentic.sharedRuleCockpit.enforcementReady', 'Validação de enforcement runtime pronta: materializações aplicadas estão disponíveis para os runtimes consumidores.')
19743
+ : this.tx('agentic.sharedRuleCockpit.enforcementWaiting', 'O enforcement runtime ainda aguarda materializações aplicadas. Publique ou revise o status de materialização antes de validar um runtime consumidor.'));
19420
19744
  await this.refreshSharedRuleTimeline();
19421
19745
  return enforcement;
19422
19746
  });
@@ -19823,14 +20147,14 @@ class DynamicPageBuilderComponent {
19823
20147
  next.ruleKey = current.ruleKey || this.resolveSharedRuleKey(next, false);
19824
20148
  this.agenticAuthoringPrompt.set(visiblePrompt);
19825
20149
  this.agenticAuthoringQuickReplies.set([]);
19826
- this.agenticAuthoringStatus.set(this.tx('agentic.status.sharedRuleTargetSelected', 'Shared-rule target selected. Continue by creating the governed definition.'));
20150
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.sharedRuleTargetSelected', 'Continue this request in the rule review.'));
19827
20151
  this.agenticAuthoringError.set('');
19828
20152
  this.agenticAuthoringPreviewResult.set(null);
19829
20153
  this.agenticAuthoringCanApply.set(false);
19830
20154
  this.agenticAuthoringSharedRuleHandoffState.set(next);
19831
20155
  this.agenticAuthoringSharedRuleHandoff.emit(next);
19832
20156
  this.appendAgenticMessage('user', visiblePrompt);
19833
- this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.targetSelected', 'Shared-rule target selected. The next safe step is creating the governed definition.'));
20157
+ this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.targetSelected', 'Rule identified. The next safe step is reviewing the rule before creating the screen.'));
19834
20158
  return true;
19835
20159
  }
19836
20160
  resolveSharedRuleQuickReplyRuleType(contextHints, text) {
@@ -20043,6 +20367,12 @@ class DynamicPageBuilderComponent {
20043
20367
  });
20044
20368
  return this.agenticComponentCapabilitiesPromise;
20045
20369
  }
20370
+ async collectRuntimeComponentObservationsForAgenticTurn() {
20371
+ if (!this.runtimeObservationRegistry) {
20372
+ return [];
20373
+ }
20374
+ return this.runtimeObservationRegistry.listActive();
20375
+ }
20046
20376
  ensureAgenticTurnController() {
20047
20377
  if (!this.agenticTurnController) {
20048
20378
  const flow = new PageBuilderAgenticAuthoringTurnFlow(this.agenticAuthoring, {
@@ -20055,6 +20385,7 @@ class DynamicPageBuilderComponent {
20055
20385
  apiKey: () => this.agenticAuthoringApiKey,
20056
20386
  enableTurnStream: () => this.agenticAuthoringEnableStreaming,
20057
20387
  includeLlmDiagnostics: () => this.agenticAuthoringIncludeLlmDiagnostics,
20388
+ collectRuntimeComponentObservations: () => this.collectRuntimeComponentObservationsForAgenticTurn(),
20058
20389
  loadComponentCapabilities: () => this.loadAgenticComponentCapabilities(),
20059
20390
  applyLocalPreview: (result) => this.applyAgenticPreviewLocally(result),
20060
20391
  describePreviewFailure: (result) => this.describeAgenticPreviewFailure(result),
@@ -20084,7 +20415,7 @@ class DynamicPageBuilderComponent {
20084
20415
  if (!applied.success && this.isAgenticTableContractError(applied.error)) {
20085
20416
  return {
20086
20417
  ...applied,
20087
- error: this.tx('agentic.errors.invalidTableContract', 'I found the data source, but the generated plan used properties that are incompatible with the table component. I will adjust it to use only supported fields.'),
20418
+ error: this.tx('agentic.errors.invalidTableContract', 'Encontrei a fonte de dados, mas a tabela proposta usa informações que esse componente não aceita. Vou ajustar para usar apenas campos compatíveis.'),
20088
20419
  };
20089
20420
  }
20090
20421
  return applied;
@@ -20096,7 +20427,7 @@ class DynamicPageBuilderComponent {
20096
20427
  this.agenticAuthoringConversation.set(state.messages);
20097
20428
  this.agenticAuthoringQuickReplies.set(state.quickReplies);
20098
20429
  this.agenticAuthoringStatus.set(handoff && !preview?.valid
20099
- ? this.tx('agentic.status.sharedRuleHandoff', 'Continue this request in the shared-rules flow.')
20430
+ ? this.tx('agentic.status.sharedRuleHandoff', 'Continue este pedido na revisão da regra.')
20100
20431
  : state.statusText);
20101
20432
  this.agenticAuthoringError.set(state.errorText);
20102
20433
  this.agenticAuthoringPreviewResult.set(preview);
@@ -20298,8 +20629,69 @@ class DynamicPageBuilderComponent {
20298
20629
  }
20299
20630
  return Object.keys(merged).length ? merged : undefined;
20300
20631
  }
20301
- consumeAgenticTurn(states$) {
20302
- return firstValueFrom(states$.pipe(concatMap((state) => from(this.applyAgenticTurnState(state)).pipe(map(() => state))), filter((state) => this.isAgenticTurnTerminalState(state)), take(1)));
20632
+ consumeAgenticTurn(states$, turnRunId) {
20633
+ return firstValueFrom(states$.pipe(takeUntil(this.agenticTurnCancel$), concatMap((state) => {
20634
+ if (!this.isCurrentAgenticTurn(turnRunId)) {
20635
+ return of(state);
20636
+ }
20637
+ return from(this.applyAgenticTurnState(state)).pipe(map(() => state));
20638
+ }), filter((state) => this.isAgenticTurnTerminalState(state)), timeout({
20639
+ first: this.agenticAuthoringTurnTerminalTimeoutMs,
20640
+ with: () => of(this.createAgenticTurnTimeoutState()),
20641
+ }), take(1))).then(async (state) => {
20642
+ if (this.isCurrentAgenticTurn(turnRunId) && this.isAgenticTurnTimeoutState(state)) {
20643
+ await this.applyAgenticTurnState(state);
20644
+ }
20645
+ return state;
20646
+ });
20647
+ }
20648
+ beginAgenticTurn() {
20649
+ this.cancelActiveAgenticTurn();
20650
+ this.agenticTurnRunId += 1;
20651
+ return this.agenticTurnRunId;
20652
+ }
20653
+ cancelActiveAgenticTurn() {
20654
+ this.agenticTurnRunId += 1;
20655
+ this.agenticTurnCancel$.next();
20656
+ }
20657
+ isCurrentAgenticTurn(turnRunId) {
20658
+ return this.agenticTurnRunId === turnRunId;
20659
+ }
20660
+ createAgenticTurnTimeoutState() {
20661
+ const message = this.tx('agentic.errors.streamTimeout', 'Ainda não consegui concluir este pedido. Tente novamente com um pedido mais específico ou revise o contexto ativo.');
20662
+ return {
20663
+ mode: 'agentic-authoring',
20664
+ state: 'error',
20665
+ phase: 'contextualize',
20666
+ statusText: '',
20667
+ errorText: message,
20668
+ messages: [
20669
+ ...this.agenticAuthoringConversation(),
20670
+ {
20671
+ id: `${Date.now()}-timeout-error`,
20672
+ role: 'error',
20673
+ text: message,
20674
+ },
20675
+ ],
20676
+ quickReplies: [],
20677
+ clarificationQuestions: [],
20678
+ contextItems: this.agenticAuthoringContextItems(),
20679
+ attachments: this.agenticAuthoringAttachments(),
20680
+ canApply: false,
20681
+ preview: null,
20682
+ diagnostics: {
20683
+ timeout: {
20684
+ schemaVersion: 'praxis-page-builder-agentic-turn-timeout.v1',
20685
+ source: 'dynamic-page-builder',
20686
+ elapsedMs: this.agenticAuthoringTurnTerminalTimeoutMs,
20687
+ },
20688
+ },
20689
+ };
20690
+ }
20691
+ isAgenticTurnTimeoutState(state) {
20692
+ const diagnostics = this.toRecord(state.diagnostics);
20693
+ const timeoutDiagnostics = this.toRecord(diagnostics?.['timeout']);
20694
+ return timeoutDiagnostics?.['source'] === 'dynamic-page-builder';
20303
20695
  }
20304
20696
  isAgenticTurnTerminalState(state) {
20305
20697
  return state.state === 'review'
@@ -20398,8 +20790,46 @@ class DynamicPageBuilderComponent {
20398
20790
  focusCanvasWidget(widgetKey) {
20399
20791
  if (!widgetKey)
20400
20792
  return;
20793
+ this.selectedWidgetKey.set(widgetKey);
20401
20794
  this.runtime?.selectWidget(widgetKey);
20402
20795
  }
20796
+ openWidgetConfiguration(widgetKey) {
20797
+ if (!widgetKey)
20798
+ return;
20799
+ this.connectionsViewerOpen.set(false);
20800
+ this.focusCanvasWidget(widgetKey);
20801
+ this.runtime?.openWidgetComponentSettings(widgetKey);
20802
+ }
20803
+ selectInsertedWidget(widgetKey, expectedWidgetCount) {
20804
+ this.selectedWidgetKey.set(widgetKey);
20805
+ this.deferInsertedWidgetFocus(widgetKey, expectedWidgetCount, 0);
20806
+ }
20807
+ deferInsertedWidgetFocus(widgetKey, expectedWidgetCount, attempt) {
20808
+ setTimeout(() => {
20809
+ const ready = this.scrollInsertedWidgetIntoView(widgetKey, expectedWidgetCount);
20810
+ if (!ready && attempt < 5) {
20811
+ this.deferInsertedWidgetFocus(widgetKey, expectedWidgetCount, attempt + 1);
20812
+ return;
20813
+ }
20814
+ setTimeout(() => this.focusCanvasWidget(widgetKey), 120);
20815
+ }, attempt === 0 ? 50 : 120);
20816
+ }
20817
+ scrollInsertedWidgetIntoView(widgetKey, expectedWidgetCount) {
20818
+ const widgets = this.hostElement.nativeElement.querySelectorAll('praxis-dynamic-page .pdx-widget');
20819
+ if (widgets.length < expectedWidgetCount) {
20820
+ return false;
20821
+ }
20822
+ const target = this.hostElement.nativeElement.querySelector(`praxis-dynamic-page .pdx-widget[data-widget-key="${this.escapeAttributeValue(widgetKey)}"]`) || widgets.item(widgets.length - 1);
20823
+ target?.scrollIntoView?.({
20824
+ block: 'center',
20825
+ inline: 'nearest',
20826
+ behavior: 'smooth',
20827
+ });
20828
+ return !!target;
20829
+ }
20830
+ escapeAttributeValue(value) {
20831
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
20832
+ }
20403
20833
  parsePage(input) {
20404
20834
  if (!input)
20405
20835
  return undefined;
@@ -20506,16 +20936,16 @@ class DynamicPageBuilderComponent {
20506
20936
  formatAgenticFailures(failureCodes) {
20507
20937
  const codes = (failureCodes ?? []).filter((code) => !!code);
20508
20938
  if (codes.length === 0) {
20509
- return this.tx('agentic.errors.invalidPreview', 'Generated preview is invalid.');
20939
+ return this.tx('agentic.errors.invalidPreview', 'Não consegui montar uma prévia segura para este pedido.');
20510
20940
  }
20511
- return `${this.tx('agentic.errors.invalidPreview', 'Generated preview is invalid.')}: ${codes.join(', ')}`;
20941
+ return this.tx('agentic.errors.invalidPreviewWithDetails', 'Não consegui montar uma prévia segura. Revise o pedido ou escolha outra fonte de dados.');
20512
20942
  }
20513
20943
  describeAgenticPreviewFailure(result) {
20514
20944
  switch (result.diagnostics?.fieldScopeDecision) {
20515
20945
  case 'rejected-duplicate-field':
20516
- return this.tx('agentic.errors.duplicateField', 'This field already exists in the selected form.');
20946
+ return this.tx('agentic.errors.duplicateField', 'Este campo existe no formulário selecionado.');
20517
20947
  case 'rejected-non-local-field-removal':
20518
- return this.tx('agentic.errors.nonLocalFieldRemoval', 'Only local fields created by AI can be removed in this flow.');
20948
+ return this.tx('agentic.errors.nonLocalFieldRemoval', ' posso remover, por aqui, campos que foram criados nesta própria prévia.');
20519
20949
  default:
20520
20950
  return this.formatAgenticFailures(result.failureCodes);
20521
20951
  }
@@ -20529,13 +20959,13 @@ class DynamicPageBuilderComponent {
20529
20959
  }
20530
20960
  switch (result.diagnostics?.fieldScopeDecision) {
20531
20961
  case 'accepted-add-local-field':
20532
- return this.tx('agentic.status.acceptedAddLocalField', 'Local field added to the form.');
20962
+ return this.tx('agentic.status.acceptedAddLocalField', 'Campo adicionado ao formulário.');
20533
20963
  case 'accepted-remove-local-field':
20534
- return this.tx('agentic.status.acceptedRemoveLocalField', 'Local field removed from the form.');
20964
+ return this.tx('agentic.status.acceptedRemoveLocalField', 'Campo removido do formulário.');
20535
20965
  case 'accepted-relabel-server-backed-field':
20536
- return this.tx('agentic.status.acceptedRelabelField', 'Field label updated.');
20966
+ return this.tx('agentic.status.acceptedRelabelField', 'Nome do campo atualizado.');
20537
20967
  default:
20538
- return this.tx('agentic.status.previewReady', 'Preview applied to the page.');
20968
+ return this.tx('agentic.status.previewReady', 'Prévia aplicada na tela.');
20539
20969
  }
20540
20970
  }
20541
20971
  isAgenticTableContractError(error) {
@@ -20558,7 +20988,7 @@ class DynamicPageBuilderComponent {
20558
20988
  }
20559
20989
  describeAgenticError(error) {
20560
20990
  if (error?.name === 'TimeoutError') {
20561
- return this.tx('agentic.errors.streamTimeout', 'The assistant took too long to finish this request. Try again with a narrower request or review the active context.');
20991
+ return this.tx('agentic.errors.streamTimeout', 'O assistente demorou para concluir este pedido. Tente de novo com um recorte menor ou revise o contexto ativo.');
20562
20992
  }
20563
20993
  if (typeof error?.error?.message === 'string' && error.error.message.trim()) {
20564
20994
  return error.error.message.trim();
@@ -20570,9 +21000,9 @@ class DynamicPageBuilderComponent {
20570
21000
  return error.message.trim();
20571
21001
  }
20572
21002
  if (typeof error?.status === 'number') {
20573
- return `HTTP ${error.status}`;
21003
+ return this.tx('agentic.errors.status', 'Não consegui concluir este pedido. Revise a conexão e tente novamente.');
20574
21004
  }
20575
- return this.tx('agentic.errors.generic', 'AI authoring failed.');
21005
+ return this.tx('agentic.errors.generic', 'Não consegui concluir este pedido.');
20576
21006
  }
20577
21007
  cloneValue(value) {
20578
21008
  if (value == null || typeof value !== 'object') {
@@ -20584,7 +21014,7 @@ class DynamicPageBuilderComponent {
20584
21014
  return resolvePraxisPageBuilderText(this.i18n, key, fallback);
20585
21015
  }
20586
21016
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, deps: [{ token: i1.MatDialog }, { token: SETTINGS_PANEL_BRIDGE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
20587
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
21017
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", componentPaletteAllowedWidgetIds: "componentPaletteAllowedWidgetIds", componentPaletteAllowedWidgetTags: "componentPaletteAllowedWidgetTags", componentPaletteAllowedPresetIds: "componentPaletteAllowedPresetIds", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
20588
21018
  providePraxisPageBuilderI18n(),
20589
21019
  { provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
20590
21020
  ], viewQueries: [{ propertyName: "runtime", first: true, predicate: ["runtime"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -20592,6 +21022,47 @@ class DynamicPageBuilderComponent {
20592
21022
  class="builder-shell"
20593
21023
  [class.builder-shell--agentic-review-rail]="agenticAuthoringReviewRailActive()"
20594
21024
  >
21025
+ @if (showSettings() && !connectionsViewerOpen() && premiumReadinessIssues().length) {
21026
+ <section
21027
+ class="builder-premium-readiness"
21028
+ data-testid="page-builder-premium-readiness"
21029
+ [attr.aria-label]="tx('premiumReadiness.title', 'Premium readiness')"
21030
+ >
21031
+ <header class="builder-premium-readiness__header">
21032
+ <span class="builder-premium-readiness__icon material-symbols-outlined" aria-hidden="true">auto_awesome</span>
21033
+ <div>
21034
+ <strong>{{ tx('premiumReadiness.title', 'Premium readiness') }}</strong>
21035
+ <p>{{ tx('premiumReadiness.subtitle', 'Qualidade visual e operacional antes de publicar.') }}</p>
21036
+ </div>
21037
+ </header>
21038
+ <ul class="builder-premium-readiness__list">
21039
+ @for (issue of premiumReadinessIssues(); track issue.id) {
21040
+ <li
21041
+ class="builder-premium-readiness__item"
21042
+ [attr.data-severity]="issue.severity"
21043
+ [attr.data-testid]="'page-builder-premium-readiness-' + issue.id"
21044
+ >
21045
+ <span class="builder-premium-readiness__severity" aria-hidden="true"></span>
21046
+ <div>
21047
+ <strong>{{ issue.title }}</strong>
21048
+ <p>{{ issue.description }}</p>
21049
+ @if (issue.action) {
21050
+ <button
21051
+ type="button"
21052
+ class="builder-premium-readiness__action"
21053
+ [attr.data-testid]="'page-builder-premium-readiness-action-' + issue.id"
21054
+ (click)="runPremiumReadinessAction(issue)"
21055
+ >
21056
+ {{ issue.action.label }}
21057
+ </button>
21058
+ }
21059
+ </div>
21060
+ </li>
21061
+ }
21062
+ </ul>
21063
+ </section>
21064
+ }
21065
+
20595
21066
  <praxis-dynamic-page
20596
21067
  #runtime
20597
21068
  [page]="currentPage()"
@@ -20658,7 +21129,7 @@ class DynamicPageBuilderComponent {
20658
21129
  (close)="minimizeAgenticAuthoring()"
20659
21130
  />
20660
21131
  }
20661
-
21132
+
20662
21133
  @if (agenticAuthoringIncludeLlmDiagnostics && agenticAuthoringLlmDiagnosticsText()) {
20663
21134
  <section
20664
21135
  class="agentic-diagnostics-panel"
@@ -20689,7 +21160,7 @@ class DynamicPageBuilderComponent {
20689
21160
  </header>
20690
21161
  @if (!agenticAuthoringLlmDiagnosticsCollapsed()) {
20691
21162
  <p class="agentic-diagnostics-panel__description">
20692
- {{ tx('agentic.diagnostics.description', 'Prompt, context bundle, and tool catalog returned by the backend for this turn.') }}
21163
+ {{ tx('agentic.diagnostics.description', 'Informações usadas para explicar como o assistente chegou à resposta deste pedido.') }}
20693
21164
  </p>
20694
21165
  <pre>{{ agenticAuthoringLlmDiagnosticsText() }}</pre>
20695
21166
  }
@@ -20702,11 +21173,11 @@ class DynamicPageBuilderComponent {
20702
21173
  [class.shared-rule-cockpit--collapsed]="sharedRuleCockpitCollapsed()"
20703
21174
  data-testid="page-builder-shared-rule-cockpit"
20704
21175
  role="region"
20705
- [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions')"
21176
+ [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra')"
20706
21177
  >
20707
21178
  <header class="shared-rule-cockpit__header">
20708
21179
  <div>
20709
- <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions') }}</strong>
21180
+ <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra') }}</strong>
20710
21181
  <span>{{ handoff.ruleKey || handoff.recommendedRuleType || handoff.flowId }}</span>
20711
21182
  </div>
20712
21183
  <div class="shared-rule-cockpit__header-actions">
@@ -20726,7 +21197,7 @@ class DynamicPageBuilderComponent {
20726
21197
  </header>
20727
21198
  @if (!sharedRuleCockpitCollapsed()) {
20728
21199
  <p class="shared-rule-cockpit__description">
20729
- {{ tx('agentic.sharedRuleCockpit.description', 'Continue the semantic decision in the governed domain-rules lifecycle. The cockpit calls canonical backend actions and only displays derived materializations.') }}
21200
+ {{ tx('agentic.sharedRuleCockpit.description', 'Continue a revisão da regra de negócio antes de criar ou salvar alterações na tela.') }}
20730
21201
  </p>
20731
21202
  <div class="shared-rule-cockpit__actions">
20732
21203
  @for (action of sharedRuleGovernedContinuationActions(); track trackGovernedContinuationAction($index, action)) {
@@ -20942,17 +21413,23 @@ class DynamicPageBuilderComponent {
20942
21413
  }
20943
21414
 
20944
21415
  <praxis-floating-toolbar
20945
- [visible]="showSettings()"
21416
+ [visible]="!!enableCustomization"
20946
21417
  [canUndo]="false"
20947
21418
  [canRedo]="false"
20948
21419
  [showSave]="canSaveCurrentPage()"
20949
21420
  [showPreview]="hasPageWidgets()"
21421
+ [editingEnabled]="showSettings()"
21422
+ [previewActive]="isPreviewMode()"
21423
+ [connectionMode]="showSettings() && connectionsViewerOpen()"
21424
+ [modeLabel]="builderModeLabel()"
21425
+ [previewLabel]="tx('toolbar.preview', 'Pré-visualizar')"
21426
+ [exitPreviewLabel]="tx('toolbar.exitPreview', 'Voltar para edição')"
20950
21427
  (add)="onAddComponent()"
20951
21428
  (settings)="openPageSettings()"
20952
21429
  (save)="saveCurrentPage()"
20953
21430
  (preview)="togglePreview()"
20954
21431
  >
20955
- @if (showPageLifecycleActions && hasPageWidgets()) {
21432
+ @if (showSettings() && showPageLifecycleActions && hasPageWidgets()) {
20956
21433
  <button
20957
21434
  pdx-toolbar-extra
20958
21435
  mat-mini-fab
@@ -20966,7 +21443,7 @@ class DynamicPageBuilderComponent {
20966
21443
  <mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
20967
21444
  </button>
20968
21445
  }
20969
- @if (showPageLifecycleActions && canDeleteSavedPage) {
21446
+ @if (showSettings() && showPageLifecycleActions && canDeleteSavedPage) {
20970
21447
  <button
20971
21448
  pdx-toolbar-extra
20972
21449
  mat-mini-fab
@@ -20981,7 +21458,7 @@ class DynamicPageBuilderComponent {
20981
21458
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
20982
21459
  </button>
20983
21460
  }
20984
- @if (enableAgenticAuthoring) {
21461
+ @if (showSettings() && enableAgenticAuthoring) {
20985
21462
  <button
20986
21463
  pdx-toolbar-extra
20987
21464
  mat-mini-fab
@@ -20997,14 +21474,17 @@ class DynamicPageBuilderComponent {
20997
21474
  <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
20998
21475
  </button>
20999
21476
  }
21000
- @if (hasPageWidgets()) {
21477
+ @if (showSettings() && hasPageWidgets()) {
21001
21478
  <button
21002
21479
  pdx-toolbar-extra
21003
21480
  mat-mini-fab
21004
21481
  type="button"
21482
+ class="builder-shell__connections-toggle"
21483
+ [class.builder-shell__connections-toggle--open]="connectionsViewerOpen()"
21005
21484
  [attr.data-testid]="'page-builder-connections-toggle'"
21006
- [matTooltip]="tx('connections.toggle', 'Edit connections')"
21007
- [attr.aria-label]="tx('connections.toggleAria', 'Edit connections')"
21485
+ [matTooltip]="connectionsToggleLabel()"
21486
+ [attr.aria-label]="connectionsToggleLabel()"
21487
+ [disabled]="!showSettings()"
21008
21488
  (click)="toggleConnectionsViewer()"
21009
21489
  >
21010
21490
  <mat-icon [praxisIcon]="'hub'"></mat-icon>
@@ -21012,7 +21492,7 @@ class DynamicPageBuilderComponent {
21012
21492
  }
21013
21493
  </praxis-floating-toolbar>
21014
21494
  </div>
21015
- `, isInline: true, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:relative;z-index:140}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: DynamicWidgetPageComponent, selector: "praxis-dynamic-page", inputs: ["page", "context", "strictValidation", "enableCustomization", "showPageSettingsButton", "shellEditorComponent", "pageEditorComponent", "autoPersist", "pageIdentity", "componentInstanceId", "showWidgetAssistantButton"], outputs: ["pageChange", "widgetEvent", "widgetSelectionChange", "widgetAssistantRequested", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo", "showSave", "showPreview"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionEditorComponent, selector: "praxis-connection-editor", inputs: ["open", "page"], outputs: ["pageChange", "focusWidget", "openPageSettings", "close"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }] });
21495
+ `, isInline: true, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.builder-premium-readiness{display:grid;grid-template-columns:minmax(220px,.72fr) minmax(0,1.28fr);gap:12px;width:100%;margin:0 0 14px;padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 72%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 10%,transparent),transparent 36%),color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #fff) 96%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface, #1d1b20) 5%,transparent)}.builder-premium-readiness__header{display:flex;align-items:flex-start;gap:10px;min-width:0}.builder-premium-readiness__header strong{display:block;font-size:13px;line-height:1.25}.builder-premium-readiness__header p,.builder-premium-readiness__item p{margin:2px 0 0;color:var(--md-sys-color-on-surface-variant, #49454f);font-size:11px;line-height:1.35}.builder-premium-readiness__icon{color:var(--md-sys-color-primary, #6750a4);font-size:20px;line-height:1}.builder-premium-readiness__list{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin:0;padding:0;list-style:none}.builder-premium-readiness__item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 64%,transparent);border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, #f7f2fa) 84%,transparent)}.builder-premium-readiness__item strong{display:block;font-size:12px;line-height:1.25}.builder-premium-readiness__action{appearance:none;display:inline-flex;align-items:center;justify-content:center;min-height:26px;margin-top:7px;padding:4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 34%,transparent);border-radius:7px;background:color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 9%,var(--md-sys-color-surface, #fff));color:var(--md-sys-color-primary, #6750a4);cursor:pointer;font:inherit;font-size:11px;font-weight:700;line-height:1.2;text-align:left}.builder-premium-readiness__severity{width:8px;height:8px;margin-top:4px;border-radius:999px;background:var(--md-sys-color-primary, #6750a4)}.builder-premium-readiness__item[data-severity=warning] .builder-premium-readiness__severity{background:var(--praxis-warning, #b26a00)}.builder-premium-readiness__item[data-severity=error] .builder-premium-readiness__severity{background:var(--md-sys-color-error, #b3261e)}@media(max-width:760px){.builder-premium-readiness{grid-template-columns:1fr}}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:fixed;inset:0;z-index:140;pointer-events:none}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.builder-shell__connections-toggle--open{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 52%,transparent);outline-offset:2px}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: DynamicWidgetPageComponent, selector: "praxis-dynamic-page", inputs: ["page", "context", "strictValidation", "enableCustomization", "showPageSettingsButton", "shellEditorComponent", "pageEditorComponent", "autoPersist", "pageIdentity", "componentInstanceId", "showWidgetAssistantButton"], outputs: ["pageChange", "widgetEvent", "widgetSelectionChange", "widgetAssistantRequested", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo", "showSave", "showPreview", "editingEnabled", "previewActive", "connectionMode", "modeLabel", "previewLabel", "exitPreviewLabel"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionEditorComponent, selector: "praxis-connection-editor", inputs: ["open", "page"], outputs: ["pageChange", "focusWidget", "openPageSettings", "close"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }] });
21016
21496
  }
21017
21497
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, decorators: [{
21018
21498
  type: Component,
@@ -21033,6 +21513,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21033
21513
  class="builder-shell"
21034
21514
  [class.builder-shell--agentic-review-rail]="agenticAuthoringReviewRailActive()"
21035
21515
  >
21516
+ @if (showSettings() && !connectionsViewerOpen() && premiumReadinessIssues().length) {
21517
+ <section
21518
+ class="builder-premium-readiness"
21519
+ data-testid="page-builder-premium-readiness"
21520
+ [attr.aria-label]="tx('premiumReadiness.title', 'Premium readiness')"
21521
+ >
21522
+ <header class="builder-premium-readiness__header">
21523
+ <span class="builder-premium-readiness__icon material-symbols-outlined" aria-hidden="true">auto_awesome</span>
21524
+ <div>
21525
+ <strong>{{ tx('premiumReadiness.title', 'Premium readiness') }}</strong>
21526
+ <p>{{ tx('premiumReadiness.subtitle', 'Qualidade visual e operacional antes de publicar.') }}</p>
21527
+ </div>
21528
+ </header>
21529
+ <ul class="builder-premium-readiness__list">
21530
+ @for (issue of premiumReadinessIssues(); track issue.id) {
21531
+ <li
21532
+ class="builder-premium-readiness__item"
21533
+ [attr.data-severity]="issue.severity"
21534
+ [attr.data-testid]="'page-builder-premium-readiness-' + issue.id"
21535
+ >
21536
+ <span class="builder-premium-readiness__severity" aria-hidden="true"></span>
21537
+ <div>
21538
+ <strong>{{ issue.title }}</strong>
21539
+ <p>{{ issue.description }}</p>
21540
+ @if (issue.action) {
21541
+ <button
21542
+ type="button"
21543
+ class="builder-premium-readiness__action"
21544
+ [attr.data-testid]="'page-builder-premium-readiness-action-' + issue.id"
21545
+ (click)="runPremiumReadinessAction(issue)"
21546
+ >
21547
+ {{ issue.action.label }}
21548
+ </button>
21549
+ }
21550
+ </div>
21551
+ </li>
21552
+ }
21553
+ </ul>
21554
+ </section>
21555
+ }
21556
+
21036
21557
  <praxis-dynamic-page
21037
21558
  #runtime
21038
21559
  [page]="currentPage()"
@@ -21099,7 +21620,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21099
21620
  (close)="minimizeAgenticAuthoring()"
21100
21621
  />
21101
21622
  }
21102
-
21623
+
21103
21624
  @if (agenticAuthoringIncludeLlmDiagnostics && agenticAuthoringLlmDiagnosticsText()) {
21104
21625
  <section
21105
21626
  class="agentic-diagnostics-panel"
@@ -21130,7 +21651,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21130
21651
  </header>
21131
21652
  @if (!agenticAuthoringLlmDiagnosticsCollapsed()) {
21132
21653
  <p class="agentic-diagnostics-panel__description">
21133
- {{ tx('agentic.diagnostics.description', 'Prompt, context bundle, and tool catalog returned by the backend for this turn.') }}
21654
+ {{ tx('agentic.diagnostics.description', 'Informações usadas para explicar como o assistente chegou à resposta deste pedido.') }}
21134
21655
  </p>
21135
21656
  <pre>{{ agenticAuthoringLlmDiagnosticsText() }}</pre>
21136
21657
  }
@@ -21143,11 +21664,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21143
21664
  [class.shared-rule-cockpit--collapsed]="sharedRuleCockpitCollapsed()"
21144
21665
  data-testid="page-builder-shared-rule-cockpit"
21145
21666
  role="region"
21146
- [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions')"
21667
+ [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra')"
21147
21668
  >
21148
21669
  <header class="shared-rule-cockpit__header">
21149
21670
  <div>
21150
- <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions') }}</strong>
21671
+ <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra') }}</strong>
21151
21672
  <span>{{ handoff.ruleKey || handoff.recommendedRuleType || handoff.flowId }}</span>
21152
21673
  </div>
21153
21674
  <div class="shared-rule-cockpit__header-actions">
@@ -21167,7 +21688,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21167
21688
  </header>
21168
21689
  @if (!sharedRuleCockpitCollapsed()) {
21169
21690
  <p class="shared-rule-cockpit__description">
21170
- {{ tx('agentic.sharedRuleCockpit.description', 'Continue the semantic decision in the governed domain-rules lifecycle. The cockpit calls canonical backend actions and only displays derived materializations.') }}
21691
+ {{ tx('agentic.sharedRuleCockpit.description', 'Continue a revisão da regra de negócio antes de criar ou salvar alterações na tela.') }}
21171
21692
  </p>
21172
21693
  <div class="shared-rule-cockpit__actions">
21173
21694
  @for (action of sharedRuleGovernedContinuationActions(); track trackGovernedContinuationAction($index, action)) {
@@ -21383,17 +21904,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21383
21904
  }
21384
21905
 
21385
21906
  <praxis-floating-toolbar
21386
- [visible]="showSettings()"
21907
+ [visible]="!!enableCustomization"
21387
21908
  [canUndo]="false"
21388
21909
  [canRedo]="false"
21389
21910
  [showSave]="canSaveCurrentPage()"
21390
21911
  [showPreview]="hasPageWidgets()"
21912
+ [editingEnabled]="showSettings()"
21913
+ [previewActive]="isPreviewMode()"
21914
+ [connectionMode]="showSettings() && connectionsViewerOpen()"
21915
+ [modeLabel]="builderModeLabel()"
21916
+ [previewLabel]="tx('toolbar.preview', 'Pré-visualizar')"
21917
+ [exitPreviewLabel]="tx('toolbar.exitPreview', 'Voltar para edição')"
21391
21918
  (add)="onAddComponent()"
21392
21919
  (settings)="openPageSettings()"
21393
21920
  (save)="saveCurrentPage()"
21394
21921
  (preview)="togglePreview()"
21395
21922
  >
21396
- @if (showPageLifecycleActions && hasPageWidgets()) {
21923
+ @if (showSettings() && showPageLifecycleActions && hasPageWidgets()) {
21397
21924
  <button
21398
21925
  pdx-toolbar-extra
21399
21926
  mat-mini-fab
@@ -21407,7 +21934,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21407
21934
  <mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
21408
21935
  </button>
21409
21936
  }
21410
- @if (showPageLifecycleActions && canDeleteSavedPage) {
21937
+ @if (showSettings() && showPageLifecycleActions && canDeleteSavedPage) {
21411
21938
  <button
21412
21939
  pdx-toolbar-extra
21413
21940
  mat-mini-fab
@@ -21422,7 +21949,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21422
21949
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
21423
21950
  </button>
21424
21951
  }
21425
- @if (enableAgenticAuthoring) {
21952
+ @if (showSettings() && enableAgenticAuthoring) {
21426
21953
  <button
21427
21954
  pdx-toolbar-extra
21428
21955
  mat-mini-fab
@@ -21438,14 +21965,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21438
21965
  <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
21439
21966
  </button>
21440
21967
  }
21441
- @if (hasPageWidgets()) {
21968
+ @if (showSettings() && hasPageWidgets()) {
21442
21969
  <button
21443
21970
  pdx-toolbar-extra
21444
21971
  mat-mini-fab
21445
21972
  type="button"
21973
+ class="builder-shell__connections-toggle"
21974
+ [class.builder-shell__connections-toggle--open]="connectionsViewerOpen()"
21446
21975
  [attr.data-testid]="'page-builder-connections-toggle'"
21447
- [matTooltip]="tx('connections.toggle', 'Edit connections')"
21448
- [attr.aria-label]="tx('connections.toggleAria', 'Edit connections')"
21976
+ [matTooltip]="connectionsToggleLabel()"
21977
+ [attr.aria-label]="connectionsToggleLabel()"
21978
+ [disabled]="!showSettings()"
21449
21979
  (click)="toggleConnectionsViewer()"
21450
21980
  >
21451
21981
  <mat-icon [praxisIcon]="'hub'"></mat-icon>
@@ -21453,7 +21983,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21453
21983
  }
21454
21984
  </praxis-floating-toolbar>
21455
21985
  </div>
21456
- `, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:relative;z-index:140}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"] }]
21986
+ `, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.builder-premium-readiness{display:grid;grid-template-columns:minmax(220px,.72fr) minmax(0,1.28fr);gap:12px;width:100%;margin:0 0 14px;padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 72%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 10%,transparent),transparent 36%),color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #fff) 96%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface, #1d1b20) 5%,transparent)}.builder-premium-readiness__header{display:flex;align-items:flex-start;gap:10px;min-width:0}.builder-premium-readiness__header strong{display:block;font-size:13px;line-height:1.25}.builder-premium-readiness__header p,.builder-premium-readiness__item p{margin:2px 0 0;color:var(--md-sys-color-on-surface-variant, #49454f);font-size:11px;line-height:1.35}.builder-premium-readiness__icon{color:var(--md-sys-color-primary, #6750a4);font-size:20px;line-height:1}.builder-premium-readiness__list{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin:0;padding:0;list-style:none}.builder-premium-readiness__item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 64%,transparent);border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, #f7f2fa) 84%,transparent)}.builder-premium-readiness__item strong{display:block;font-size:12px;line-height:1.25}.builder-premium-readiness__action{appearance:none;display:inline-flex;align-items:center;justify-content:center;min-height:26px;margin-top:7px;padding:4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 34%,transparent);border-radius:7px;background:color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 9%,var(--md-sys-color-surface, #fff));color:var(--md-sys-color-primary, #6750a4);cursor:pointer;font:inherit;font-size:11px;font-weight:700;line-height:1.2;text-align:left}.builder-premium-readiness__severity{width:8px;height:8px;margin-top:4px;border-radius:999px;background:var(--md-sys-color-primary, #6750a4)}.builder-premium-readiness__item[data-severity=warning] .builder-premium-readiness__severity{background:var(--praxis-warning, #b26a00)}.builder-premium-readiness__item[data-severity=error] .builder-premium-readiness__severity{background:var(--md-sys-color-error, #b3261e)}@media(max-width:760px){.builder-premium-readiness{grid-template-columns:1fr}}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:fixed;inset:0;z-index:140;pointer-events:none}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.builder-shell__connections-toggle--open{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 52%,transparent);outline-offset:2px}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"] }]
21457
21987
  }], ctorParameters: () => [{ type: i1.MatDialog }, { type: undefined, decorators: [{
21458
21988
  type: Optional
21459
21989
  }, {
@@ -21480,6 +22010,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21480
22010
  type: Input
21481
22011
  }], pageEditorComponent: [{
21482
22012
  type: Input
22013
+ }], componentPaletteAllowedWidgetIds: [{
22014
+ type: Input
22015
+ }], componentPaletteAllowedWidgetTags: [{
22016
+ type: Input
22017
+ }], componentPaletteAllowedPresetIds: [{
22018
+ type: Input
21483
22019
  }], enableAgenticAuthoring: [{
21484
22020
  type: Input
21485
22021
  }], agenticAuthoringProvider: [{