@xpert-ai/plugin-live-dashboard 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/.xpertai-plugin/plugin.json +1 -1
  2. package/README.md +8 -2
  3. package/dist/index.js +3 -1
  4. package/dist/lib/agent.schema.d.ts +177 -23
  5. package/dist/lib/agent.schema.js +11 -9
  6. package/dist/lib/archive.service.d.ts +169 -0
  7. package/dist/lib/archive.service.js +147 -0
  8. package/dist/lib/bounded-map.d.ts +2 -0
  9. package/dist/lib/bounded-map.js +25 -0
  10. package/dist/lib/capacity.d.ts +14 -0
  11. package/dist/lib/capacity.js +16 -0
  12. package/dist/lib/content.provider.d.ts +1 -1
  13. package/dist/lib/dashboard-archive.d.ts +70 -0
  14. package/dist/lib/dashboard-archive.js +118 -0
  15. package/dist/lib/dashboard-queries.d.ts +1 -1
  16. package/dist/lib/dashboard-queries.js +11 -6
  17. package/dist/lib/dashboard-receipt.js +1 -1
  18. package/dist/lib/dashboard-sources.d.ts +69 -0
  19. package/dist/lib/dashboard-sources.js +38 -0
  20. package/dist/lib/dashboard-view.schema.d.ts +422 -88
  21. package/dist/lib/dashboard.schema.d.ts +379 -58
  22. package/dist/lib/dashboard.schema.js +20 -2
  23. package/dist/lib/dashboard.service.d.ts +80 -15
  24. package/dist/lib/dashboard.service.js +65 -9
  25. package/dist/lib/definition-tools.d.ts +4 -4
  26. package/dist/lib/document-host.js +1 -1
  27. package/dist/lib/document-package.d.ts +19 -4
  28. package/dist/lib/editing-patch.d.ts +3 -0
  29. package/dist/lib/editing-patch.js +4 -2
  30. package/dist/lib/editing-session.d.ts +4 -4
  31. package/dist/lib/editing.d.ts +204 -20
  32. package/dist/lib/editing.js +10 -3
  33. package/dist/lib/filter-evidence.d.ts +28 -0
  34. package/dist/lib/filter-evidence.js +3 -2
  35. package/dist/lib/html-guidance.d.ts +1 -0
  36. package/dist/lib/html-guidance.js +2 -1
  37. package/dist/lib/html-validation-feedback.d.ts +7 -0
  38. package/dist/lib/html-validation-feedback.js +19 -0
  39. package/dist/lib/html-validation.js +3 -2
  40. package/dist/lib/inspection-host.d.ts +7 -0
  41. package/dist/lib/inspection-host.js +48 -0
  42. package/dist/lib/inspection-runtime.d.ts +2 -0
  43. package/dist/lib/inspection-runtime.js +77 -0
  44. package/dist/lib/json-input.d.ts +4 -0
  45. package/dist/lib/json-input.js +21 -0
  46. package/dist/lib/middleware.d.ts +3 -1
  47. package/dist/lib/middleware.js +92 -13
  48. package/dist/lib/plugin.js +3 -1
  49. package/dist/lib/presentation.provider.d.ts +24 -9
  50. package/dist/lib/presentation.provider.js +2 -1
  51. package/dist/lib/preview-retry.d.ts +4 -3
  52. package/dist/lib/preview-retry.js +13 -7
  53. package/dist/lib/prompt-workflows.js +1 -1
  54. package/dist/lib/query-session.d.ts +9 -0
  55. package/dist/lib/query-session.js +64 -0
  56. package/dist/lib/save-requests.d.ts +118 -0
  57. package/dist/lib/save-requests.js +199 -0
  58. package/dist/lib/source-executions.d.ts +437 -0
  59. package/dist/lib/source-executions.js +49 -0
  60. package/dist/lib/source-validation.d.ts +2 -0
  61. package/dist/lib/source-validation.js +21 -0
  62. package/dist/lib/view.provider.d.ts +213 -8
  63. package/dist/lib/view.provider.js +47 -5
  64. package/dist/remote/app.css +1 -1
  65. package/dist/remote/app.js +185 -63
  66. package/dist/remote/build-manifest.json +52 -33
  67. package/dist/sandbox-actions/action.json +1 -1
  68. package/dist/sandbox-actions/bundle/host.js +63 -14
  69. package/dist/sandbox-actions/bundle/validate.mjs +2 -2
  70. package/dist/validation/host-entry.d.ts +5 -1
  71. package/dist/validation/host-entry.js +21 -4
  72. package/docs/docs.json +5 -1
  73. package/docs/large-dashboards-acceptance.mdx +74 -0
  74. package/docs/large-dashboards.mdx +80 -0
  75. package/docs/sources-inspect-portability-acceptance.mdx +67 -0
  76. package/docs/sources-inspect-portability.mdx +115 -0
  77. package/package.json +8 -7
  78. package/skills/live-dashboard/SKILL.md +5 -4
  79. package/skills/live-dashboard/references/source-inspection.md +17 -0
@@ -1,3 +1,4 @@
1
+ import type { DashboardSaveRequests } from './save-requests';
1
2
  import { z } from 'zod/v3';
2
3
  import type { AnalyticsBinding, XpertResolvedViewHostContext } from '@xpert-ai/contracts';
3
4
  import { type IAgentMiddlewareContext } from '@xpert-ai/plugin-sdk';
@@ -6,6 +7,66 @@ import { DashboardService } from './dashboard.service';
6
7
  import { type DashboardSelection } from './editing-session';
7
8
  export { dashboardSelectionSchema, dashboardContextSchema } from './editing-session';
8
9
  export declare const updateToolSchema: z.ZodObject<{
10
+ sourceMetadata: z.ZodOptional<z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
11
+ bindingId: z.ZodString;
12
+ title: z.ZodString;
13
+ description: z.ZodOptional<z.ZodString>;
14
+ }, "strict", z.ZodTypeAny, {
15
+ bindingId: string;
16
+ title: string;
17
+ description?: string | undefined;
18
+ }, {
19
+ bindingId: string;
20
+ title: string;
21
+ description?: string | undefined;
22
+ }>, "many">, {
23
+ bindingId: string;
24
+ title: string;
25
+ description?: string | undefined;
26
+ }[], unknown>>>;
27
+ components: z.ZodOptional<z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
28
+ id: z.ZodString;
29
+ elementId: z.ZodString;
30
+ title: z.ZodString;
31
+ kind: z.ZodEnum<["metric", "chart", "table", "filter", "text"]>;
32
+ sources: z.ZodArray<z.ZodObject<{
33
+ bindingId: z.ZodString;
34
+ fieldIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
35
+ }, "strict", z.ZodTypeAny, {
36
+ bindingId: string;
37
+ fieldIds?: string[] | undefined;
38
+ }, {
39
+ bindingId: string;
40
+ fieldIds?: string[] | undefined;
41
+ }>, "many">;
42
+ }, "strict", z.ZodTypeAny, {
43
+ title: string;
44
+ id: string;
45
+ elementId: string;
46
+ kind: "filter" | "metric" | "chart" | "table" | "text";
47
+ sources: {
48
+ bindingId: string;
49
+ fieldIds?: string[] | undefined;
50
+ }[];
51
+ }, {
52
+ title: string;
53
+ id: string;
54
+ elementId: string;
55
+ kind: "filter" | "metric" | "chart" | "table" | "text";
56
+ sources: {
57
+ bindingId: string;
58
+ fieldIds?: string[] | undefined;
59
+ }[];
60
+ }>, "many">, {
61
+ title: string;
62
+ id: string;
63
+ elementId: string;
64
+ kind: "filter" | "metric" | "chart" | "table" | "text";
65
+ sources: {
66
+ bindingId: string;
67
+ fieldIds?: string[] | undefined;
68
+ }[];
69
+ }[], unknown>>>;
9
70
  controls: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
10
71
  controlId: z.ZodString;
11
72
  type: z.ZodEnum<["string", "number", "boolean", "date"]>;
@@ -42,24 +103,24 @@ export declare const updateToolSchema: z.ZodObject<{
42
103
  color: z.ZodOptional<z.ZodString>;
43
104
  }, "strict", z.ZodTypeAny, {
44
105
  type: "bar" | "line" | "area" | "pie" | "scatter";
45
- id: string;
46
106
  title: string;
107
+ id: string;
47
108
  datasetId: string;
48
109
  x: string;
49
110
  y: string;
50
111
  color?: string | undefined;
51
112
  }, {
52
113
  type: "bar" | "line" | "area" | "pie" | "scatter";
53
- id: string;
54
114
  title: string;
115
+ id: string;
55
116
  datasetId: string;
56
117
  x: string;
57
118
  y: string;
58
119
  color?: string | undefined;
59
120
  }>, "many">, {
60
121
  type: "bar" | "line" | "area" | "pie" | "scatter";
61
- id: string;
62
122
  title: string;
123
+ id: string;
63
124
  datasetId: string;
64
125
  x: string;
65
126
  y: string;
@@ -71,18 +132,18 @@ export declare const updateToolSchema: z.ZodObject<{
71
132
  datasetId: z.ZodString;
72
133
  fields: z.ZodArray<z.ZodString, "many">;
73
134
  }, "strict", z.ZodTypeAny, {
74
- id: string;
75
135
  title: string;
136
+ id: string;
76
137
  datasetId: string;
77
138
  fields: string[];
78
139
  }, {
79
- id: string;
80
140
  title: string;
141
+ id: string;
81
142
  datasetId: string;
82
143
  fields: string[];
83
144
  }>, "many">, {
84
- id: string;
85
145
  title: string;
146
+ id: string;
86
147
  datasetId: string;
87
148
  fields: string[];
88
149
  }[], unknown>>;
@@ -94,16 +155,19 @@ export declare const updateToolSchema: z.ZodObject<{
94
155
  controlIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
95
156
  viewIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
96
157
  htmlElementIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
158
+ componentIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
97
159
  }, "strict", z.ZodTypeAny, {
98
160
  bindingIds: string[];
99
161
  controlIds: string[];
100
162
  viewIds: string[];
101
163
  htmlElementIds: string[];
164
+ componentIds: string[];
102
165
  }, {
103
166
  bindingIds?: string[] | undefined;
104
167
  controlIds?: string[] | undefined;
105
168
  viewIds?: string[] | undefined;
106
169
  htmlElementIds?: string[] | undefined;
170
+ componentIds?: string[] | undefined;
107
171
  }>>;
108
172
  title: z.ZodString;
109
173
  editId: z.ZodString;
@@ -116,6 +180,21 @@ export declare const updateToolSchema: z.ZodObject<{
116
180
  expectedRevision: number;
117
181
  expectedCurrentVersionId: string | null;
118
182
  editId: string;
183
+ sourceMetadata?: {
184
+ bindingId: string;
185
+ title: string;
186
+ description?: string | undefined;
187
+ }[] | undefined;
188
+ components?: {
189
+ title: string;
190
+ id: string;
191
+ elementId: string;
192
+ kind: "filter" | "metric" | "chart" | "table" | "text";
193
+ sources: {
194
+ bindingId: string;
195
+ fieldIds?: string[] | undefined;
196
+ }[];
197
+ }[] | undefined;
119
198
  controls?: {
120
199
  type: "string" | "number" | "boolean" | "date";
121
200
  controlId: string;
@@ -125,16 +204,16 @@ export declare const updateToolSchema: z.ZodObject<{
125
204
  }[] | undefined;
126
205
  charts?: {
127
206
  type: "bar" | "line" | "area" | "pie" | "scatter";
128
- id: string;
129
207
  title: string;
208
+ id: string;
130
209
  datasetId: string;
131
210
  x: string;
132
211
  y: string;
133
212
  color?: string | undefined;
134
213
  }[] | undefined;
135
214
  tables?: {
136
- id: string;
137
215
  title: string;
216
+ id: string;
138
217
  datasetId: string;
139
218
  fields: string[];
140
219
  }[] | undefined;
@@ -146,6 +225,7 @@ export declare const updateToolSchema: z.ZodObject<{
146
225
  controlIds: string[];
147
226
  viewIds: string[];
148
227
  htmlElementIds: string[];
228
+ componentIds: string[];
149
229
  } | undefined;
150
230
  htmlPath?: string | undefined;
151
231
  }, {
@@ -153,6 +233,8 @@ export declare const updateToolSchema: z.ZodObject<{
153
233
  expectedRevision: number;
154
234
  expectedCurrentVersionId: string | null;
155
235
  editId: string;
236
+ sourceMetadata?: unknown;
237
+ components?: unknown;
156
238
  controls?: unknown;
157
239
  charts?: unknown;
158
240
  tables?: unknown;
@@ -164,12 +246,13 @@ export declare const updateToolSchema: z.ZodObject<{
164
246
  controlIds?: string[] | undefined;
165
247
  viewIds?: string[] | undefined;
166
248
  htmlElementIds?: string[] | undefined;
249
+ componentIds?: string[] | undefined;
167
250
  } | undefined;
168
251
  htmlPath?: string | undefined;
169
252
  }>;
170
- export declare const EDITING_GUIDANCE = "Opening or reading a dashboard does not modify it. A selection_required result is normal: show its message to the user and wait for an explicit selection; do not retry, infer a target from history, or create a replacement. Do not save an unchanged editing copy or reopen/update merely to confirm a successful save; use the mutation receipt. For existing dashboards, call dashboard_open first and inspect presentation.type. For standard dashboards, update definition fields directly: a rename needs only title, editId, expectedRevision and expectedCurrentVersionId. No HTML file exists; omit htmlPath and libraries. For HTML dashboards only, open prepares a unique editing copy at htmlPath. Read with sandbox_read_file. If a long HTML line is truncated, do not repeat the same read: use dashboard_read_html with editId and follow nextOffset until null to inspect the saved source, then apply exact replacements to htmlPath. Never replace a file with a truncated preview. Edit with sandbox_edit_file/multi_edit_file (sandbox_write_file is create-only), then call dashboard_update with that exact htmlPath and read revisions. If the user requests a rename, include the new title in this same update; editing the HTML heading alone does not rename the Artifact. Save each batch automatically without human confirmation. Files are not dashboard saves. Preserve Binding semantics, stable component IDs and dependency locks unless requested. Update arrays upsert by ID, preserving omitted components; removals must name explicitly requested deletions. HTML updates retain existing element IDs. For new HTML, assign stable IDs to every KPI, chart, detail table and filter. Read and patch the current file instead of rebuilding unrelated sections. On conflict retain the editing file, open the latest draft and reconcile; never silently overwrite. Historical versions are read-only references. All Agent saves are drafts; only the Workbench human publish action creates formal versions. Read the live-dashboard skill for the complete workflow.";
253
+ export declare const EDITING_GUIDANCE = "Opening or reading a dashboard does not modify it. A selection_required result is normal: show its message to the user and wait for an explicit selection; do not retry, infer a target from history, or create a replacement. Do not save an unchanged editing copy or reopen/update merely to confirm a successful save; use the mutation receipt. For existing dashboards, call dashboard_open first and inspect presentation.type. For standard dashboards, update definition fields directly: a rename needs only title, editId, expectedRevision and expectedCurrentVersionId. No HTML file exists; omit htmlPath and libraries. For HTML dashboards only, open prepares a unique editing copy at htmlPath. Read with sandbox_read_file. If a long HTML line is truncated, do not repeat the same read: use dashboard_read_html with editId and follow nextOffset until null to inspect the saved source, then apply exact replacements to htmlPath. Never replace a file with a truncated preview. Edit with sandbox_edit_file/multi_edit_file (sandbox_write_file is create-only), then call dashboard_update with that exact htmlPath and read revisions. If the user requests a rename, include the new title in this same update; editing the HTML heading alone does not rename the Artifact. Save each batch automatically without human confirmation. Files are not dashboard saves. Preserve Binding semantics, stable component IDs and dependency locks unless requested. To add filters to an existing Binding, copy its complete dashboard_open.bindings[] entry, retain binding.id and existing parameters[].controlId, and call dashboard_preview_binding after changing payload/parameters/defaults. Binding ID is independent of output.datasetId; simplified dashboard_preview derives the ID from datasetId and can accidentally add a new Binding instead of updating the old one. Use the stable Binding ID in HTML query/subscribe calls. Submit every intended changed/new Binding previewId and matching controls with htmlPath in the same dashboard_update. Update arrays upsert by ID, preserving omitted components; removals must name explicitly requested deletions. On preflight failure, compare expected/requested Binding IDs, repair the HTML or previews, and retain all intended previewIds, controls, title and htmlPath when retrying. Dropping previewIds does not register new HTML queries. Do not remove an existing Binding merely to suppress validation. HTML updates retain existing element IDs. For new HTML, assign stable IDs to every KPI, chart, detail table and filter. Read and patch the current file instead of rebuilding unrelated sections. On conflict retain the editing file, open the latest draft and reconcile; never silently overwrite. Historical versions are read-only references. All Agent saves are drafts; only the Workbench human publish action creates formal versions. Read the live-dashboard skill for the complete workflow.";
171
254
  /** Run-local read receipts carry planning versions; authorization and CAS remain in the domain service. */
172
- export declare function createEditingTools(service: DashboardService, scope: XpertResolvedViewHostContext, context: IAgentMiddlewareContext, resolvePreviews: (ids: string[]) => AnalyticsBinding[], validateFinal: (manifest: DashboardManifest, requirePreviews: boolean, changedBindingIds?: string[]) => void, onOpen?: (path: string, artifactId: string) => void, currentTarget?: (config: unknown) => DashboardSelection | null | undefined): (import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
255
+ export declare function createEditingTools(service: DashboardService, scope: XpertResolvedViewHostContext, context: IAgentMiddlewareContext, resolvePreviews: (ids: string[]) => AnalyticsBinding[], validateFinal: (manifest: DashboardManifest, requirePreviews: boolean, changedBindingIds?: string[]) => void, onOpen?: (path: string, artifactId: string) => void, currentTarget?: (config: unknown) => DashboardSelection | null | undefined, saveRequests?: DashboardSaveRequests): (import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
173
256
  page: z.ZodDefault<z.ZodNumber>;
174
257
  }, "strict", z.ZodTypeAny, {
175
258
  page: number;
@@ -217,6 +300,66 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
217
300
  }, {
218
301
  artifactId?: string | undefined;
219
302
  }, string> | import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
303
+ sourceMetadata: z.ZodOptional<z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
304
+ bindingId: z.ZodString;
305
+ title: z.ZodString;
306
+ description: z.ZodOptional<z.ZodString>;
307
+ }, "strict", z.ZodTypeAny, {
308
+ bindingId: string;
309
+ title: string;
310
+ description?: string | undefined;
311
+ }, {
312
+ bindingId: string;
313
+ title: string;
314
+ description?: string | undefined;
315
+ }>, "many">, {
316
+ bindingId: string;
317
+ title: string;
318
+ description?: string | undefined;
319
+ }[], unknown>>>;
320
+ components: z.ZodOptional<z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
321
+ id: z.ZodString;
322
+ elementId: z.ZodString;
323
+ title: z.ZodString;
324
+ kind: z.ZodEnum<["metric", "chart", "table", "filter", "text"]>;
325
+ sources: z.ZodArray<z.ZodObject<{
326
+ bindingId: z.ZodString;
327
+ fieldIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
328
+ }, "strict", z.ZodTypeAny, {
329
+ bindingId: string;
330
+ fieldIds?: string[] | undefined;
331
+ }, {
332
+ bindingId: string;
333
+ fieldIds?: string[] | undefined;
334
+ }>, "many">;
335
+ }, "strict", z.ZodTypeAny, {
336
+ title: string;
337
+ id: string;
338
+ elementId: string;
339
+ kind: "filter" | "metric" | "chart" | "table" | "text";
340
+ sources: {
341
+ bindingId: string;
342
+ fieldIds?: string[] | undefined;
343
+ }[];
344
+ }, {
345
+ title: string;
346
+ id: string;
347
+ elementId: string;
348
+ kind: "filter" | "metric" | "chart" | "table" | "text";
349
+ sources: {
350
+ bindingId: string;
351
+ fieldIds?: string[] | undefined;
352
+ }[];
353
+ }>, "many">, {
354
+ title: string;
355
+ id: string;
356
+ elementId: string;
357
+ kind: "filter" | "metric" | "chart" | "table" | "text";
358
+ sources: {
359
+ bindingId: string;
360
+ fieldIds?: string[] | undefined;
361
+ }[];
362
+ }[], unknown>>>;
220
363
  controls: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
221
364
  controlId: z.ZodString;
222
365
  type: z.ZodEnum<["string", "number", "boolean", "date"]>;
@@ -253,24 +396,24 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
253
396
  color: z.ZodOptional<z.ZodString>;
254
397
  }, "strict", z.ZodTypeAny, {
255
398
  type: "bar" | "line" | "area" | "pie" | "scatter";
256
- id: string;
257
399
  title: string;
400
+ id: string;
258
401
  datasetId: string;
259
402
  x: string;
260
403
  y: string;
261
404
  color?: string | undefined;
262
405
  }, {
263
406
  type: "bar" | "line" | "area" | "pie" | "scatter";
264
- id: string;
265
407
  title: string;
408
+ id: string;
266
409
  datasetId: string;
267
410
  x: string;
268
411
  y: string;
269
412
  color?: string | undefined;
270
413
  }>, "many">, {
271
414
  type: "bar" | "line" | "area" | "pie" | "scatter";
272
- id: string;
273
415
  title: string;
416
+ id: string;
274
417
  datasetId: string;
275
418
  x: string;
276
419
  y: string;
@@ -282,18 +425,18 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
282
425
  datasetId: z.ZodString;
283
426
  fields: z.ZodArray<z.ZodString, "many">;
284
427
  }, "strict", z.ZodTypeAny, {
285
- id: string;
286
428
  title: string;
429
+ id: string;
287
430
  datasetId: string;
288
431
  fields: string[];
289
432
  }, {
290
- id: string;
291
433
  title: string;
434
+ id: string;
292
435
  datasetId: string;
293
436
  fields: string[];
294
437
  }>, "many">, {
295
- id: string;
296
438
  title: string;
439
+ id: string;
297
440
  datasetId: string;
298
441
  fields: string[];
299
442
  }[], unknown>>;
@@ -305,16 +448,19 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
305
448
  controlIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
306
449
  viewIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
307
450
  htmlElementIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
451
+ componentIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
308
452
  }, "strict", z.ZodTypeAny, {
309
453
  bindingIds: string[];
310
454
  controlIds: string[];
311
455
  viewIds: string[];
312
456
  htmlElementIds: string[];
457
+ componentIds: string[];
313
458
  }, {
314
459
  bindingIds?: string[] | undefined;
315
460
  controlIds?: string[] | undefined;
316
461
  viewIds?: string[] | undefined;
317
462
  htmlElementIds?: string[] | undefined;
463
+ componentIds?: string[] | undefined;
318
464
  }>>;
319
465
  title: z.ZodString;
320
466
  editId: z.ZodString;
@@ -327,6 +473,21 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
327
473
  expectedRevision: number;
328
474
  expectedCurrentVersionId: string | null;
329
475
  editId: string;
476
+ sourceMetadata?: {
477
+ bindingId: string;
478
+ title: string;
479
+ description?: string | undefined;
480
+ }[] | undefined;
481
+ components?: {
482
+ title: string;
483
+ id: string;
484
+ elementId: string;
485
+ kind: "filter" | "metric" | "chart" | "table" | "text";
486
+ sources: {
487
+ bindingId: string;
488
+ fieldIds?: string[] | undefined;
489
+ }[];
490
+ }[] | undefined;
330
491
  controls?: {
331
492
  type: "string" | "number" | "boolean" | "date";
332
493
  controlId: string;
@@ -336,16 +497,16 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
336
497
  }[] | undefined;
337
498
  charts?: {
338
499
  type: "bar" | "line" | "area" | "pie" | "scatter";
339
- id: string;
340
500
  title: string;
501
+ id: string;
341
502
  datasetId: string;
342
503
  x: string;
343
504
  y: string;
344
505
  color?: string | undefined;
345
506
  }[] | undefined;
346
507
  tables?: {
347
- id: string;
348
508
  title: string;
509
+ id: string;
349
510
  datasetId: string;
350
511
  fields: string[];
351
512
  }[] | undefined;
@@ -357,6 +518,7 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
357
518
  controlIds: string[];
358
519
  viewIds: string[];
359
520
  htmlElementIds: string[];
521
+ componentIds: string[];
360
522
  } | undefined;
361
523
  htmlPath?: string | undefined;
362
524
  }, {
@@ -364,6 +526,8 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
364
526
  expectedRevision: number;
365
527
  expectedCurrentVersionId: string | null;
366
528
  editId: string;
529
+ sourceMetadata?: unknown;
530
+ components?: unknown;
367
531
  controls?: unknown;
368
532
  charts?: unknown;
369
533
  tables?: unknown;
@@ -375,6 +539,7 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
375
539
  controlIds?: string[] | undefined;
376
540
  viewIds?: string[] | undefined;
377
541
  htmlElementIds?: string[] | undefined;
542
+ componentIds?: string[] | undefined;
378
543
  } | undefined;
379
544
  htmlPath?: string | undefined;
380
545
  }>, {
@@ -382,6 +547,21 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
382
547
  expectedRevision: number;
383
548
  expectedCurrentVersionId: string | null;
384
549
  editId: string;
550
+ sourceMetadata?: {
551
+ bindingId: string;
552
+ title: string;
553
+ description?: string | undefined;
554
+ }[] | undefined;
555
+ components?: {
556
+ title: string;
557
+ id: string;
558
+ elementId: string;
559
+ kind: "filter" | "metric" | "chart" | "table" | "text";
560
+ sources: {
561
+ bindingId: string;
562
+ fieldIds?: string[] | undefined;
563
+ }[];
564
+ }[] | undefined;
385
565
  controls?: {
386
566
  type: "string" | "number" | "boolean" | "date";
387
567
  controlId: string;
@@ -391,16 +571,16 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
391
571
  }[] | undefined;
392
572
  charts?: {
393
573
  type: "bar" | "line" | "area" | "pie" | "scatter";
394
- id: string;
395
574
  title: string;
575
+ id: string;
396
576
  datasetId: string;
397
577
  x: string;
398
578
  y: string;
399
579
  color?: string | undefined;
400
580
  }[] | undefined;
401
581
  tables?: {
402
- id: string;
403
582
  title: string;
583
+ id: string;
404
584
  datasetId: string;
405
585
  fields: string[];
406
586
  }[] | undefined;
@@ -412,6 +592,7 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
412
592
  controlIds: string[];
413
593
  viewIds: string[];
414
594
  htmlElementIds: string[];
595
+ componentIds: string[];
415
596
  } | undefined;
416
597
  htmlPath?: string | undefined;
417
598
  }, {
@@ -419,6 +600,8 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
419
600
  expectedRevision: number;
420
601
  expectedCurrentVersionId: string | null;
421
602
  editId: string;
603
+ sourceMetadata?: unknown;
604
+ components?: unknown;
422
605
  controls?: unknown;
423
606
  charts?: unknown;
424
607
  tables?: unknown;
@@ -430,6 +613,7 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
430
613
  controlIds?: string[] | undefined;
431
614
  viewIds?: string[] | undefined;
432
615
  htmlElementIds?: string[] | undefined;
616
+ componentIds?: string[] | undefined;
433
617
  } | undefined;
434
618
  htmlPath?: string | undefined;
435
619
  }, string>)[];
@@ -23,9 +23,9 @@ exports.updateToolSchema = agent_schema_1.createToolSchema.omit({ creationIntent
23
23
  libraries: document_libraries_1.libraryRequestsSchema.optional().describe('Omit to preserve the saved dependency versions. Supply the complete desired library IDs to explicitly add, remove or upgrade bundled libraries.') }).strict();
24
24
  const readHtmlSchema = v3_1.z.object({ editId: v3_1.z.string().uuid(), versionId: v3_1.z.string().uuid().optional().describe('Only for historical inspection; copy readVersionId from dashboard_open.'), offset: v3_1.z.number().int().min(0).max(300000).default(0),
25
25
  length: v3_1.z.number().int().min(1).max(24000).default(16000) }).strict();
26
- exports.EDITING_GUIDANCE = `Opening or reading a dashboard does not modify it. A selection_required result is normal: show its message to the user and wait for an explicit selection; do not retry, infer a target from history, or create a replacement. Do not save an unchanged editing copy or reopen/update merely to confirm a successful save; use the mutation receipt. For existing dashboards, call dashboard_open first and inspect presentation.type. For standard dashboards, update definition fields directly: a rename needs only title, editId, expectedRevision and expectedCurrentVersionId. No HTML file exists; omit htmlPath and libraries. For HTML dashboards only, open prepares a unique editing copy at htmlPath. Read with sandbox_read_file. If a long HTML line is truncated, do not repeat the same read: use dashboard_read_html with editId and follow nextOffset until null to inspect the saved source, then apply exact replacements to htmlPath. Never replace a file with a truncated preview. Edit with sandbox_edit_file/multi_edit_file (sandbox_write_file is create-only), then call dashboard_update with that exact htmlPath and read revisions. If the user requests a rename, include the new title in this same update; editing the HTML heading alone does not rename the Artifact. Save each batch automatically without human confirmation. Files are not dashboard saves. Preserve Binding semantics, stable component IDs and dependency locks unless requested. Update arrays upsert by ID, preserving omitted components; removals must name explicitly requested deletions. HTML updates retain existing element IDs. For new HTML, assign stable IDs to every KPI, chart, detail table and filter. Read and patch the current file instead of rebuilding unrelated sections. On conflict retain the editing file, open the latest draft and reconcile; never silently overwrite. Historical versions are read-only references. All Agent saves are drafts; only the Workbench human publish action creates formal versions. Read the live-dashboard skill for the complete workflow.`;
26
+ exports.EDITING_GUIDANCE = `Opening or reading a dashboard does not modify it. A selection_required result is normal: show its message to the user and wait for an explicit selection; do not retry, infer a target from history, or create a replacement. Do not save an unchanged editing copy or reopen/update merely to confirm a successful save; use the mutation receipt. For existing dashboards, call dashboard_open first and inspect presentation.type. For standard dashboards, update definition fields directly: a rename needs only title, editId, expectedRevision and expectedCurrentVersionId. No HTML file exists; omit htmlPath and libraries. For HTML dashboards only, open prepares a unique editing copy at htmlPath. Read with sandbox_read_file. If a long HTML line is truncated, do not repeat the same read: use dashboard_read_html with editId and follow nextOffset until null to inspect the saved source, then apply exact replacements to htmlPath. Never replace a file with a truncated preview. Edit with sandbox_edit_file/multi_edit_file (sandbox_write_file is create-only), then call dashboard_update with that exact htmlPath and read revisions. If the user requests a rename, include the new title in this same update; editing the HTML heading alone does not rename the Artifact. Save each batch automatically without human confirmation. Files are not dashboard saves. Preserve Binding semantics, stable component IDs and dependency locks unless requested. To add filters to an existing Binding, copy its complete dashboard_open.bindings[] entry, retain binding.id and existing parameters[].controlId, and call dashboard_preview_binding after changing payload/parameters/defaults. Binding ID is independent of output.datasetId; simplified dashboard_preview derives the ID from datasetId and can accidentally add a new Binding instead of updating the old one. Use the stable Binding ID in HTML query/subscribe calls. Submit every intended changed/new Binding previewId and matching controls with htmlPath in the same dashboard_update. Update arrays upsert by ID, preserving omitted components; removals must name explicitly requested deletions. On preflight failure, compare expected/requested Binding IDs, repair the HTML or previews, and retain all intended previewIds, controls, title and htmlPath when retrying. Dropping previewIds does not register new HTML queries. Do not remove an existing Binding merely to suppress validation. HTML updates retain existing element IDs. For new HTML, assign stable IDs to every KPI, chart, detail table and filter. Read and patch the current file instead of rebuilding unrelated sections. On conflict retain the editing file, open the latest draft and reconcile; never silently overwrite. Historical versions are read-only references. All Agent saves are drafts; only the Workbench human publish action creates formal versions. Read the live-dashboard skill for the complete workflow.`;
27
27
  /** Run-local read receipts carry planning versions; authorization and CAS remain in the domain service. */
28
- function createEditingTools(service, scope, context, resolvePreviews, validateFinal, onOpen = () => undefined, currentTarget = editing_session_1.selectionFromConfig) {
28
+ function createEditingTools(service, scope, context, resolvePreviews, validateFinal, onOpen = () => undefined, currentTarget = editing_session_1.selectionFromConfig, saveRequests) {
29
29
  const target = (input, config) => {
30
30
  const selected = currentTarget(config);
31
31
  if (input.artifactId)
@@ -61,7 +61,7 @@ function createEditingTools(service, scope, context, resolvePreviews, validateFi
61
61
  : { state: 'published', versionNumber: saved.versionNumber ?? 0, versionId: resolved.versionId }) }, config);
62
62
  return JSON.stringify({ resourceCard, editId, expectedCurrentVersionId: saved.baseVersionId ?? saved.versionId ?? null, ...(resolved.versionId ? { readVersionId: resolved.versionId } : {}), expectedRevision: saved.draftRevision ?? 0, state: saved.isDraft ? 'draft' : 'published', artifactId: saved.artifactId, versionId: saved.versionId, versionNumber: saved.versionNumber,
63
63
  ...definition, presentation: presentation ? { type: 'html', characters: presentation.html.length, dependencies: presentation.dependencies ?? [] } : { type: 'standard' },
64
- ...(resolved.versionId ? { next: 'Read-only published version. To edit, select the working draft in the Workbench version selector or explicitly open this Artifact without a versionId, then use its current draft revision. Publication requires a separate human action.' } : htmlPath ? { htmlPath, saveArguments: { editId, expectedRevision: saved.draftRevision ?? 0, expectedCurrentVersionId: saved.baseVersionId ?? saved.versionId ?? null, title: saved.manifest.title, htmlPath }, editingFile: { path: htmlPath, exists: true, hasUnsavedChanges: false, writeMode: 'edit_existing', read: { tool: 'sandbox_read_file', arguments: { file_path: htmlPath } } }, next: 'Opening only prepared a copy; it did not change the dashboard and requires no save. Call dashboard_update only after applying requested changes. Copy saveArguments, replacing title with the requested new name when renaming. expectedCurrentVersionId must remain actual JSON null or the returned UUID; never a string such as None. When repairing a failed update, retain all intended changes instead of dropping title. The editing file already exists: do not use sandbox_write_file on it. When renaming, include title and htmlPath together in one dashboard_update. A private editing copy is ready. Read it with sandbox_read_file. If long lines are truncated, use dashboard_read_html with editId and follow nextOffset until null instead of retrying file reads. This fallback reads the saved source; apply changes to htmlPath and never write a truncated preview. Edit with sandbox_edit_file/multi_edit_file, then save using dashboard_update with this htmlPath and the returned revisions. File edits alone do not save the dashboard.' } : !presentation ? { next: 'Standard dashboard: update definition fields directly. A rename requires only title plus editId, expectedRevision and expectedCurrentVersionId. No HTML editing file exists; omit htmlPath and libraries unless intentionally converting to HTML.' } : {}) });
64
+ ...(resolved.versionId ? { next: 'Read-only published version. To edit, select the working draft in the Workbench version selector or explicitly open this Artifact without a versionId, then use its current draft revision. Publication requires a separate human action.' } : htmlPath ? { htmlPath, saveArguments: { editId, expectedRevision: saved.draftRevision ?? 0, expectedCurrentVersionId: saved.baseVersionId ?? saved.versionId ?? null, title: saved.manifest.title, htmlPath }, editingFile: { path: htmlPath, exists: true, hasUnsavedChanges: false, writeMode: 'edit_existing', read: { tool: 'sandbox_read_file', arguments: { file_path: htmlPath } } }, next: 'Opening only prepared a copy; it did not change the dashboard and requires no save. Call dashboard_update only after applying requested changes. Copy saveArguments, replacing title with the requested new name when renaming. expectedCurrentVersionId must remain actual JSON null or the returned UUID; never a string such as None. When repairing a failed update, retain all intended previewIds, controls, title and htmlPath. For changed bindings, copy bindings[] and preserve binding.id via dashboard_preview_binding; omitted bindings remain saved. The editing file already exists: do not use sandbox_write_file on it. When renaming, include title and htmlPath together in one dashboard_update. A private editing copy is ready. Read it with sandbox_read_file. If long lines are truncated, use dashboard_read_html with editId and follow nextOffset until null instead of retrying file reads. This fallback reads the saved source; apply changes to htmlPath and never write a truncated preview. Edit with sandbox_edit_file/multi_edit_file, then save using dashboard_update with this htmlPath and the returned revisions. File edits alone do not save the dashboard.' } : !presentation ? { next: 'Standard dashboard: update definition fields directly. A rename requires only title plus editId, expectedRevision and expectedCurrentVersionId. No HTML editing file exists; omit htmlPath and libraries unless intentionally converting to HTML.' } : {}) });
65
65
  }, { name: 'dashboard_open', description: 'Read one authorized saved dashboard and obtain its stable editId and current draft revision. For a current HTML dashboard also prepares a unique Workspace editing copy without changing the Artifact. Historical versions remain read-only. Omit artifactId only for the selected Workbench dashboard.',
66
66
  schema: targetSchema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Read dashboard for editing', zh_Hans: '读取看板以继续修改' } } }),
67
67
  (0, tools_1.tool)(async (input) => {
@@ -89,6 +89,8 @@ function createEditingTools(service, scope, context, resolvePreviews, validateFi
89
89
  const changedBindings = previewIds ? resolvePreviews(previewIds) : undefined;
90
90
  const bindings = (0, editing_patch_1.upsertComponents)(saved.manifest.bindings, changedBindings, item => item.id, removals?.bindingIds);
91
91
  const controls = (0, editing_patch_1.upsertComponents)(saved.manifest.controls, changes.controls, item => item.controlId, removals?.controlIds);
92
+ const sourceMetadata = (0, editing_patch_1.upsertComponents)(saved.manifest.sourceMetadata ?? [], changes.sourceMetadata, item => item.bindingId, removals?.bindingIds.filter(id => saved.manifest.sourceMetadata?.some(item => item.bindingId === id)));
93
+ const components = (0, editing_patch_1.upsertComponents)(saved.manifest.components ?? [], changes.components, item => item.id, removals?.componentIds);
92
94
  if (removals?.viewIds.some(id => ![...saved.manifest.charts, ...saved.manifest.tables].some(view => view.id === id)))
93
95
  throw new Error('DASHBOARD_REMOVAL_INVALID: copy existing view IDs');
94
96
  const charts = (0, editing_patch_1.upsertComponents)(saved.manifest.charts, changes.charts, item => item.id, removals?.viewIds.filter(id => saved.manifest.charts.some(item => item.id === id)));
@@ -114,8 +116,13 @@ function createEditingTools(service, scope, context, resolvePreviews, validateFi
114
116
  }
115
117
  (0, editing_patch_1.assertHtmlPreserved)(saved.manifest.presentation, presentation, removals?.htmlElementIds);
116
118
  const manifest = dashboard_schema_1.dashboardSchema.parse({ ...saved.manifest, ...changes, bindings, controls, charts, tables,
119
+ ...(sourceMetadata.length || saved.manifest.sourceMetadata ? { sourceMetadata } : {}), ...(components.length || saved.manifest.components ? { components } : {}),
117
120
  ...(presentation ? { presentation } : {}) });
118
121
  validateFinal(manifest, previewIds !== undefined, changedBindings?.map(item => item.id));
122
+ if (saveRequests && manifest.bindings.length > 8) {
123
+ const key = (0, node_crypto_1.createHash)('sha256').update(JSON.stringify([editId, expectedRevision, expectedCurrentVersionId, manifest, sourceFile])).digest('hex');
124
+ return JSON.stringify(await saveRequests.submit(scope, manifest, expectedCurrentVersionId, expectedRevision, key, sourceFile));
125
+ }
119
126
  const { schema, id, ...update } = manifest;
120
127
  const result = await service.update(scope, editId, expectedRevision, update, expectedCurrentVersionId);
121
128
  const resourceCard = await (0, resource_card_1.emitDashboardCard)(scope, { ...result, state: 'draft', revision: result.draftRevision }, config);
@@ -1,6 +1,34 @@
1
1
  import { z } from 'zod/v3';
2
2
  import type { AnalyticsBinding, AnalyticsValue, XpertResolvedViewHostContext } from '@xpert-ai/contracts';
3
3
  import type { DashboardService } from './dashboard.service';
4
+ export declare const filterTestSchema: z.ZodObject<{
5
+ previewId: z.ZodString;
6
+ controls: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, Record<string, string | number | boolean | null>, unknown>;
7
+ expectations: z.ZodEffects<z.ZodArray<z.ZodObject<{
8
+ fieldId: z.ZodString;
9
+ oneOf: z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, "many">;
10
+ }, "strict", z.ZodTypeAny, {
11
+ fieldId: string;
12
+ oneOf: (string | number | boolean | null)[];
13
+ }, {
14
+ fieldId: string;
15
+ oneOf: (string | number | boolean | null)[];
16
+ }>, "many">, {
17
+ fieldId: string;
18
+ oneOf: (string | number | boolean | null)[];
19
+ }[], unknown>;
20
+ }, "strict", z.ZodTypeAny, {
21
+ controls: Record<string, string | number | boolean | null>;
22
+ previewId: string;
23
+ expectations: {
24
+ fieldId: string;
25
+ oneOf: (string | number | boolean | null)[];
26
+ }[];
27
+ }, {
28
+ previewId: string;
29
+ controls?: unknown;
30
+ expectations?: unknown;
31
+ }>;
4
32
  /** Model quality evidence, not authorization: every query still goes through Analytics. */
5
33
  export declare function createFilterEvidence(service: DashboardService, scope: XpertResolvedViewHostContext, previews: Map<string, AnalyticsBinding>): {
6
34
  requirements(binding: AnalyticsBinding, previewId: string, rows: Record<string, AnalyticsValue>[]): {
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterTestSchema = void 0;
3
4
  exports.createFilterEvidence = createFilterEvidence;
4
5
  const tools_1 = require("@langchain/core/tools");
5
6
  const v3_1 = require("zod/v3");
6
7
  const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
7
8
  const scalar = v3_1.z.union([v3_1.z.string().max(4000), v3_1.z.number().finite(), v3_1.z.boolean(), v3_1.z.null()]);
8
- const schema = v3_1.z.object({ previewId: v3_1.z.string().min(1),
9
+ exports.filterTestSchema = v3_1.z.object({ previewId: v3_1.z.string().min(1),
9
10
  controls: (0, plugin_sdk_1.jsonEncodedSchema)(v3_1.z.record(scalar)),
10
11
  expectations: (0, plugin_sdk_1.jsonEncodedSchema)(v3_1.z.array(v3_1.z.object({ fieldId: v3_1.z.string().min(1), oneOf: v3_1.z.array(scalar).min(1).max(100) }).strict()).min(1).max(24))
11
12
  }).strict();
@@ -55,6 +56,6 @@ function createFilterEvidence(service, scope, previews) {
55
56
  checked.set(input.previewId, controls);
56
57
  return JSON.stringify({ previewId: input.previewId, passed: true, checkedControls: [...controls], remainingControls: required(binding, input.previewId).map(parameter => parameter.controlId), rows: dataset.rows.slice(0, 20), completeness: dataset.completeness });
57
58
  }, { name: 'dashboard_test_filter', description: 'Verify a previewed Binding with concrete filter values and expected field values. For a nullable dimension selector, test a real non-null value and expect every row of the matching field to equal it before saving. Does not change defaults. A failed check must be repaired before create/update.',
58
- schema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Verify filter results', zh_Hans: '验证筛选结果' } } })
59
+ schema: exports.filterTestSchema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Verify filter results', zh_Hans: '验证筛选结果' } } })
59
60
  };
60
61
  }
@@ -1 +1,2 @@
1
1
  export declare const HTML_DASHBOARD_GUIDANCE = "For free-layout HTML dashboards, read the installed live-dashboard skill's references/html-runtime.md through read_skill_file, relative to its SKILL.md path in the skill catalog. Create/edit the HTML with SandboxFile; then dashboard_create_html or dashboard_update validates and saves it. Do not use generic present_files to save or preview a live dashboard. Its preview belongs to the Live dashboards Workbench. Call dashboard_libraries for packaged ECharts/Three.js. Network access is temporarily unrestricted for functional acceptance. CDN scripts/styles/fonts, CSS imports, external images and fetch/XHR are available under browser CORS and mixed-content rules. Tailwind CDN is supported; do not remove styling to avoid network validation. Platform business data remains declarative Binding queries through window.xpertLiveArtifact; never embed credentials. The page MUST declare const live = window.xpertLiveArtifact in its script (live is not a host global), register live.subscribe(bindingId, render), await live.ready(), and invoke live.query(bindingId, typedControls) for initial data and filter changes. window.__datasets and window.__refresh are not platform APIs and are never populated by the host. Read the runtime reference and its html-lifecycle.md example before writing HTML; preserve that lifecycle while freely changing the layout. Use one complete Dataset for KPI, trend and details when they share the same metric and filters; do not create a redundant unfiltered total Binding. Never let filtered and unfiltered subscriptions both write the same KPI: a refresh would race and overwrite the selected-region total. Distinct global totals need distinct, clearly labeled elements. Native data selects require data-dashboard-control=\"<controlId>\"; purely visual selects use data-dashboard-presentation. A data filter must query, not only filter cached browser rows. bindSelect controls ONE binding only. For a shared dimension filter across multiple bindings, follow the skill custom-select example and query every affected binding with the same typed controls; matching control IDs do not broadcast automatically. bindSelect derives options from Dataset fields and is only for dimension filters. Fixed query enums (days, page size, granularity) need options from parameter.allowedValues and a typed change listener calling live.query; never use date rows as numeric day-count options.";
2
+ export declare const HTML_QUERY_ROUNDS = "For a filter shared by multiple Bindings use await live.queryMany(affectedBindingIds, typedControls); render explicit failures from the returned {datasets, failures}. Successful subscriptions are delivered together after that round settles. Individual live.query calls retain independent delivery for legacy pages.";
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HTML_DASHBOARD_GUIDANCE = void 0;
3
+ exports.HTML_QUERY_ROUNDS = exports.HTML_DASHBOARD_GUIDANCE = void 0;
4
4
  exports.HTML_DASHBOARD_GUIDANCE = `For free-layout HTML dashboards, read the installed live-dashboard skill's references/html-runtime.md through read_skill_file, relative to its SKILL.md path in the skill catalog. Create/edit the HTML with SandboxFile; then dashboard_create_html or dashboard_update validates and saves it. Do not use generic present_files to save or preview a live dashboard. Its preview belongs to the Live dashboards Workbench. Call dashboard_libraries for packaged ECharts/Three.js. Network access is temporarily unrestricted for functional acceptance. CDN scripts/styles/fonts, CSS imports, external images and fetch/XHR are available under browser CORS and mixed-content rules. Tailwind CDN is supported; do not remove styling to avoid network validation. Platform business data remains declarative Binding queries through window.xpertLiveArtifact; never embed credentials. The page MUST declare const live = window.xpertLiveArtifact in its script (live is not a host global), register live.subscribe(bindingId, render), await live.ready(), and invoke live.query(bindingId, typedControls) for initial data and filter changes. window.__datasets and window.__refresh are not platform APIs and are never populated by the host. Read the runtime reference and its html-lifecycle.md example before writing HTML; preserve that lifecycle while freely changing the layout. Use one complete Dataset for KPI, trend and details when they share the same metric and filters; do not create a redundant unfiltered total Binding. Never let filtered and unfiltered subscriptions both write the same KPI: a refresh would race and overwrite the selected-region total. Distinct global totals need distinct, clearly labeled elements. Native data selects require data-dashboard-control="<controlId>"; purely visual selects use data-dashboard-presentation. A data filter must query, not only filter cached browser rows. bindSelect controls ONE binding only. For a shared dimension filter across multiple bindings, follow the skill custom-select example and query every affected binding with the same typed controls; matching control IDs do not broadcast automatically. bindSelect derives options from Dataset fields and is only for dimension filters. Fixed query enums (days, page size, granularity) need options from parameter.allowedValues and a typed change listener calling live.query; never use date rows as numeric day-count options.`;
5
+ exports.HTML_QUERY_ROUNDS = 'For a filter shared by multiple Bindings use await live.queryMany(affectedBindingIds, typedControls); render explicit failures from the returned {datasets, failures}. Successful subscriptions are delivered together after that round settles. Individual live.query calls retain independent delivery for legacy pages.';
@@ -0,0 +1,7 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ import type { DashboardManifest } from './dashboard.schema';
3
+ /** Report only binding identities observed by validation, never query payloads or returned rows. */
4
+ export declare function htmlPreflightFailure(manifest: DashboardManifest, report: {
5
+ errors: string[];
6
+ requestedBindings: string[];
7
+ }): BadRequestException;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.htmlPreflightFailure = htmlPreflightFailure;
4
+ const common_1 = require("@nestjs/common");
5
+ /** Report only binding identities observed by validation, never query payloads or returned rows. */
6
+ function htmlPreflightFailure(manifest, report) {
7
+ const expectedBindingIds = manifest.bindings.map(binding => binding.id);
8
+ const requestedBindingIds = [...new Set(report.requestedBindings)];
9
+ const expected = new Set(expectedBindingIds), requested = new Set(requestedBindingIds);
10
+ const bindingDiagnostics = {
11
+ expectedBindingIds, requestedBindingIds,
12
+ missingQueryBindingIds: expectedBindingIds.filter(id => !requested.has(id)),
13
+ unexpectedQueryBindingIds: requestedBindingIds.filter(id => !expected.has(id))
14
+ };
15
+ const repair = 'Compare the candidate manifest Binding IDs with the HTML query/subscribe IDs. Requested IDs are observed calls, not a static list of every HTML reference. For an existing Binding, preserve dashboard_open.bindings[].id and preview its complete edited Binding with dashboard_preview_binding. Include all intended current-run previewIds, controls and htmlPath together in dashboard_update; omitted components remain saved. Add new Bindings only for new data needs; remove existing ones only for explicitly requested deletions. Repair other reported page errors before retrying. No dashboard was saved.';
16
+ // Some tool hosts retain only Error.message, so keep the bounded identity diagnostics there too.
17
+ return new common_1.BadRequestException({ code: 'DASHBOARD_HTML_PREFLIGHT_FAILED', errors: report.errors,
18
+ bindingDiagnostics, message: `DASHBOARD_HTML_PREFLIGHT_FAILED: ${JSON.stringify(report.errors)}. Binding diagnostics: ${JSON.stringify(bindingDiagnostics)}. ${repair}` });
19
+ }