@xpert-ai/plugin-live-dashboard 0.3.1 → 0.4.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.
Files changed (148) hide show
  1. package/.xpertai-plugin/plugin.json +10 -2
  2. package/README.md +6 -0
  3. package/assets/branding/cover-v1.prompt.txt +27 -0
  4. package/assets/branding/cover-v1.webp +0 -0
  5. package/assets/previews/customer-brief.png +0 -0
  6. package/assets/previews/profit-atlas.png +0 -0
  7. package/assets/previews/trend-workspace.png +0 -0
  8. package/dist/index.js +6 -3
  9. package/dist/lib/agent.schema.d.ts +43 -37
  10. package/dist/lib/agent.schema.js +2 -1
  11. package/dist/lib/app-config.d.ts +62 -0
  12. package/dist/lib/app-config.js +38 -0
  13. package/dist/lib/artifact-type.provider.d.ts +15 -0
  14. package/dist/lib/artifact-type.provider.js +78 -0
  15. package/dist/lib/assistant-template.d.ts +1 -2
  16. package/dist/lib/assistant-template.js +3 -52
  17. package/dist/lib/content.provider.js +13 -5
  18. package/dist/lib/dashboard-navigation.d.ts +58 -14
  19. package/dist/lib/dashboard-navigation.js +11 -10
  20. package/dist/lib/dashboard-view.schema.d.ts +278 -46
  21. package/dist/lib/dashboard-view.schema.js +9 -1
  22. package/dist/lib/dashboard.service.d.ts +49 -3
  23. package/dist/lib/dashboard.service.js +64 -28
  24. package/dist/lib/document-libraries.d.ts +1 -1
  25. package/dist/lib/document-libraries.js +3 -2
  26. package/dist/lib/document-network.d.ts +1 -1
  27. package/dist/lib/document-network.js +2 -6
  28. package/dist/lib/editing-feedback.d.ts +5 -0
  29. package/dist/lib/editing-feedback.js +19 -0
  30. package/dist/lib/editing-patch.d.ts +22 -0
  31. package/dist/lib/editing-patch.js +46 -0
  32. package/dist/lib/editing-session.d.ts +167 -0
  33. package/dist/lib/editing-session.js +53 -0
  34. package/dist/lib/editing.d.ts +92 -60
  35. package/dist/lib/editing.js +36 -24
  36. package/dist/lib/html-guidance.d.ts +1 -1
  37. package/dist/lib/html-guidance.js +1 -1
  38. package/dist/lib/middleware.js +42 -18
  39. package/dist/lib/monitor.d.ts +70 -0
  40. package/dist/lib/monitor.js +101 -0
  41. package/dist/lib/plugin.js +4 -1
  42. package/dist/lib/project.d.ts +106 -0
  43. package/dist/lib/project.js +17 -0
  44. package/dist/lib/projects.schema.d.ts +63 -0
  45. package/dist/lib/projects.schema.js +8 -0
  46. package/dist/lib/projects.service.d.ts +25 -0
  47. package/dist/lib/projects.service.js +75 -0
  48. package/dist/lib/resource-card.js +1 -1
  49. package/dist/lib/runtime-context.d.ts +3 -0
  50. package/dist/lib/runtime-context.js +13 -0
  51. package/dist/lib/save-evidence.d.ts +1 -1
  52. package/dist/lib/templates.d.ts +2 -0
  53. package/dist/lib/templates.js +55 -0
  54. package/dist/lib/view.provider.d.ts +127 -8
  55. package/dist/lib/view.provider.js +49 -12
  56. package/dist/libraries/TREND-WORKSPACE-ICONS-LICENSE.txt +43 -0
  57. package/dist/libraries/catalog.json +1 -1
  58. package/dist/remote/app.css +1 -1
  59. package/dist/remote/app.js +34 -34
  60. package/dist/remote/build-manifest.json +116 -32
  61. package/dist/sandbox-actions/action.json +1 -1
  62. package/dist/sandbox-actions/bundle/host.js +2 -2
  63. package/dist/sandbox-actions/bundle/resource-cache.mjs +2 -1
  64. package/dist/sandbox-actions/bundle/validate.mjs +1 -1
  65. package/docs/docs.json +7 -0
  66. package/docs/frontend-libraries.mdx +12 -4
  67. package/docs/html-mode.md +3 -3
  68. package/docs/quick-start-acceptance.mdx +50 -0
  69. package/docs/quick-start.mdx +64 -0
  70. package/docs/superstore.mdx +38 -0
  71. package/docs/team-sharing.mdx +6 -2
  72. package/docs/trend-workspace-acceptance.mdx +43 -0
  73. package/docs/trend-workspace.mdx +30 -0
  74. package/docs/verification.mdx +4 -2
  75. package/docs/visual-styles-acceptance.mdx +40 -0
  76. package/docs/visual-styles.mdx +46 -0
  77. package/package.json +23 -17
  78. package/skills/live-dashboard/SKILL.md +27 -3
  79. package/skills/live-dashboard/examples/README.md +25 -0
  80. package/skills/live-dashboard/examples/catalog.json +79 -0
  81. package/skills/live-dashboard/examples/production-quality/README.md +25 -0
  82. package/skills/live-dashboard/examples/production-quality/dashboard.html +129 -0
  83. package/skills/live-dashboard/examples/production-quality/definition.json +67 -0
  84. package/skills/live-dashboard/examples/production-quality/demo.csv +7 -0
  85. package/skills/live-dashboard/examples/production-quality/demo.json +44 -0
  86. package/skills/live-dashboard/examples/production-quality/expected.json +26 -0
  87. package/skills/live-dashboard/examples/production-quality/preview.png +0 -0
  88. package/skills/live-dashboard/examples/production-quality/query.json +53 -0
  89. package/skills/live-dashboard/examples/regional-sales/README.md +25 -0
  90. package/skills/live-dashboard/examples/regional-sales/dashboard-create.json +35 -0
  91. package/skills/live-dashboard/examples/regional-sales/definition.json +35 -0
  92. package/skills/live-dashboard/examples/regional-sales/demo.csv +5 -0
  93. package/skills/live-dashboard/examples/regional-sales/demo.json +18 -0
  94. package/skills/live-dashboard/examples/regional-sales/expected.json +19 -0
  95. package/skills/live-dashboard/examples/regional-sales/preview.png +0 -0
  96. package/skills/live-dashboard/examples/regional-sales/query.json +45 -0
  97. package/skills/live-dashboard/examples/sales-overview/README.md +25 -0
  98. package/skills/live-dashboard/examples/sales-overview/dashboard.html +129 -0
  99. package/skills/live-dashboard/examples/sales-overview/definition.json +57 -0
  100. package/skills/live-dashboard/examples/sales-overview/demo.csv +7 -0
  101. package/skills/live-dashboard/examples/sales-overview/demo.json +38 -0
  102. package/skills/live-dashboard/examples/sales-overview/expected.json +22 -0
  103. package/skills/live-dashboard/examples/sales-overview/preview.png +0 -0
  104. package/skills/live-dashboard/examples/sales-overview/query.json +52 -0
  105. package/skills/live-dashboard/examples/superstore/README.md +64 -0
  106. package/skills/live-dashboard/examples/superstore/THIRD_PARTY_LICENSE.txt +207 -0
  107. package/skills/live-dashboard/examples/superstore/build_data.py +155 -0
  108. package/skills/live-dashboard/examples/superstore/build_pages.py +129 -0
  109. package/skills/live-dashboard/examples/superstore/checks.json +104 -0
  110. package/skills/live-dashboard/examples/superstore/customers-mobile-dark.png +0 -0
  111. package/skills/live-dashboard/examples/superstore/customers-select.png +0 -0
  112. package/skills/live-dashboard/examples/superstore/customers.html +316 -0
  113. package/skills/live-dashboard/examples/superstore/customers.png +0 -0
  114. package/skills/live-dashboard/examples/superstore/customers.queries.json +512 -0
  115. package/skills/live-dashboard/examples/superstore/expected.json +4069 -0
  116. package/skills/live-dashboard/examples/superstore/import.json +200 -0
  117. package/skills/live-dashboard/examples/superstore/orders.csv +10195 -0
  118. package/skills/live-dashboard/examples/superstore/overview-mobile-dark.png +0 -0
  119. package/skills/live-dashboard/examples/superstore/overview-select.png +0 -0
  120. package/skills/live-dashboard/examples/superstore/overview.html +310 -0
  121. package/skills/live-dashboard/examples/superstore/overview.png +0 -0
  122. package/skills/live-dashboard/examples/superstore/overview.queries.json +636 -0
  123. package/skills/live-dashboard/examples/superstore/page.js +109 -0
  124. package/skills/live-dashboard/examples/superstore/profitability-mobile-dark.png +0 -0
  125. package/skills/live-dashboard/examples/superstore/profitability-select.png +0 -0
  126. package/skills/live-dashboard/examples/superstore/profitability.html +307 -0
  127. package/skills/live-dashboard/examples/superstore/profitability.png +0 -0
  128. package/skills/live-dashboard/examples/superstore/profitability.queries.json +334 -0
  129. package/skills/live-dashboard/examples/superstore/provenance.json +24 -0
  130. package/skills/live-dashboard/examples/superstore/semantic-model.json +220 -0
  131. package/skills/live-dashboard/examples/superstore/test_data.py +62 -0
  132. package/skills/live-dashboard/references/html-runtime.md +1 -1
  133. package/skills/live-dashboard/themes/README.md +50 -0
  134. package/skills/live-dashboard/themes/customer-brief/README.md +47 -0
  135. package/skills/live-dashboard/themes/customer-brief/charts.js +17 -0
  136. package/skills/live-dashboard/themes/customer-brief/layout.html +22 -0
  137. package/skills/live-dashboard/themes/customer-brief/theme.css +108 -0
  138. package/skills/live-dashboard/themes/profit-atlas/README.md +43 -0
  139. package/skills/live-dashboard/themes/profit-atlas/charts.js +30 -0
  140. package/skills/live-dashboard/themes/profit-atlas/layout.html +19 -0
  141. package/skills/live-dashboard/themes/profit-atlas/theme.css +75 -0
  142. package/skills/live-dashboard/themes/trend-workspace/ICON_LICENSE.txt +43 -0
  143. package/skills/live-dashboard/themes/trend-workspace/README.md +144 -0
  144. package/skills/live-dashboard/themes/trend-workspace/charts.js +60 -0
  145. package/skills/live-dashboard/themes/trend-workspace/icons.js +11 -0
  146. package/skills/live-dashboard/themes/trend-workspace/layout.html +45 -0
  147. package/skills/live-dashboard/themes/trend-workspace/select.js +127 -0
  148. package/skills/live-dashboard/themes/trend-workspace/theme.css +137 -0
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardStateSchema = exports.dashboardContextSchema = exports.dashboardSelectionSchema = void 0;
4
+ exports.editingSession = editingSession;
5
+ exports.selectionFromContext = selectionFromContext;
6
+ exports.selectionFromConfig = selectionFromConfig;
7
+ const v3_1 = require("zod/v3");
8
+ exports.dashboardSelectionSchema = v3_1.z.object({ schemaVersion: v3_1.z.literal(1), artifactId: v3_1.z.string().uuid(),
9
+ versionId: v3_1.z.string().uuid().optional(), draftRevision: v3_1.z.number().int().positive().optional() }).strict();
10
+ const newSelection = v3_1.z.object({ schemaVersion: v3_1.z.literal(1), mode: v3_1.z.literal('new') }).strict();
11
+ exports.dashboardContextSchema = v3_1.z.object({ live_dashboard: v3_1.z.union([exports.dashboardSelectionSchema, newSelection]).nullable().optional() });
12
+ exports.dashboardStateSchema = v3_1.z.object({ dashboardEditing: v3_1.z.object({
13
+ scope: v3_1.z.string(), target: exports.dashboardSelectionSchema.nullable()
14
+ }).nullable().optional() });
15
+ /** Checkpoints belong to an actor and conversation. Copied state must never choose another user's target. */
16
+ function editingSession(context) {
17
+ const scope = JSON.stringify([context.tenantId, context.organizationId, context.userId, context.xpertId,
18
+ context.projectId, context.conversationId, context.threadId, context.agentKey]);
19
+ let active = null;
20
+ let initialized = false;
21
+ return {
22
+ current: () => active,
23
+ resolve(config) { return initialized ? active : selectionFromConfig(config) ?? active; },
24
+ restore(state, requestContext) {
25
+ const persisted = exports.dashboardStateSchema.safeParse(state);
26
+ const selected = selectionFromContext(requestContext);
27
+ active = selected !== undefined ? selected : persisted.success && persisted.data.dashboardEditing?.scope === scope
28
+ ? persisted.data.dashboardEditing.target : null;
29
+ initialized = true;
30
+ return { dashboardEditing: { scope, target: active } };
31
+ },
32
+ select(target) { active = target; initialized = true; return { dashboardEditing: { scope, target } }; }
33
+ };
34
+ }
35
+ function selectionFromContext(value) {
36
+ if (value === undefined || value === null)
37
+ return undefined;
38
+ const parsed = exports.dashboardContextSchema.safeParse(value);
39
+ if (!parsed.success)
40
+ throw new Error('DASHBOARD_SELECTION_INVALID: select the dashboard again before editing');
41
+ if (parsed.data.live_dashboard === undefined)
42
+ return undefined;
43
+ const selected = parsed.data.live_dashboard;
44
+ return selected && 'artifactId' in selected ? selected : null;
45
+ }
46
+ function selectionFromConfig(value) {
47
+ const config = v3_1.z.object({ context: v3_1.z.unknown(),
48
+ configurable: v3_1.z.object({ context: v3_1.z.unknown() }).optional() }).safeParse(value);
49
+ if (!config.success)
50
+ return undefined;
51
+ const primary = selectionFromContext(config.data.context);
52
+ return primary !== undefined ? primary : selectionFromContext(config.data.configurable?.context);
53
+ }
@@ -3,56 +3,9 @@ import type { AnalyticsBinding, XpertResolvedViewHostContext } from '@xpert-ai/c
3
3
  import { type IAgentMiddlewareContext } from '@xpert-ai/plugin-sdk';
4
4
  import { type DashboardManifest } from './dashboard.schema';
5
5
  import { DashboardService } from './dashboard.service';
6
- export declare const dashboardSelectionSchema: z.ZodObject<{
7
- schemaVersion: z.ZodLiteral<1>;
8
- artifactId: z.ZodString;
9
- versionId: z.ZodOptional<z.ZodString>;
10
- draftRevision: z.ZodOptional<z.ZodNumber>;
11
- }, "strict", z.ZodTypeAny, {
12
- artifactId: string;
13
- schemaVersion: 1;
14
- versionId?: string | undefined;
15
- draftRevision?: number | undefined;
16
- }, {
17
- artifactId: string;
18
- schemaVersion: 1;
19
- versionId?: string | undefined;
20
- draftRevision?: number | undefined;
21
- }>;
22
- export declare const dashboardContextSchema: z.ZodObject<{
23
- live_dashboard: z.ZodOptional<z.ZodNullable<z.ZodObject<{
24
- schemaVersion: z.ZodLiteral<1>;
25
- artifactId: z.ZodString;
26
- versionId: z.ZodOptional<z.ZodString>;
27
- draftRevision: z.ZodOptional<z.ZodNumber>;
28
- }, "strict", z.ZodTypeAny, {
29
- artifactId: string;
30
- schemaVersion: 1;
31
- versionId?: string | undefined;
32
- draftRevision?: number | undefined;
33
- }, {
34
- artifactId: string;
35
- schemaVersion: 1;
36
- versionId?: string | undefined;
37
- draftRevision?: number | undefined;
38
- }>>>;
39
- }, "strip", z.ZodTypeAny, {
40
- live_dashboard?: {
41
- artifactId: string;
42
- schemaVersion: 1;
43
- versionId?: string | undefined;
44
- draftRevision?: number | undefined;
45
- } | null | undefined;
46
- }, {
47
- live_dashboard?: {
48
- artifactId: string;
49
- schemaVersion: 1;
50
- versionId?: string | undefined;
51
- draftRevision?: number | undefined;
52
- } | null | undefined;
53
- }>;
6
+ import { type DashboardSelection } from './editing-session';
7
+ export { dashboardSelectionSchema, dashboardContextSchema } from './editing-session';
54
8
  export declare const updateToolSchema: z.ZodObject<{
55
- supersedesPaths: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
56
9
  controls: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
57
10
  controlId: z.ZodString;
58
11
  type: z.ZodEnum<["string", "number", "boolean", "date"]>;
@@ -133,14 +86,31 @@ export declare const updateToolSchema: z.ZodObject<{
133
86
  datasetId: string;
134
87
  fields: string[];
135
88
  }[], unknown>>;
89
+ supersedesPaths: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
136
90
  previewIds: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], unknown>>;
137
91
  } & {
92
+ removals: z.ZodOptional<z.ZodObject<{
93
+ bindingIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
94
+ controlIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
95
+ viewIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
96
+ htmlElementIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
97
+ }, "strict", z.ZodTypeAny, {
98
+ bindingIds: string[];
99
+ controlIds: string[];
100
+ viewIds: string[];
101
+ htmlElementIds: string[];
102
+ }, {
103
+ bindingIds?: string[] | undefined;
104
+ controlIds?: string[] | undefined;
105
+ viewIds?: string[] | undefined;
106
+ htmlElementIds?: string[] | undefined;
107
+ }>>;
138
108
  title: z.ZodString;
139
109
  editId: z.ZodString;
140
110
  expectedRevision: z.ZodNumber;
141
111
  expectedCurrentVersionId: z.ZodNullable<z.ZodString>;
142
112
  htmlPath: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>>;
143
- libraries: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEnum<["echarts", "three"]>, "many">, ("echarts" | "three")[], ("echarts" | "three")[]>>;
113
+ libraries: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["echarts", "three", "trend-workspace", "profit-atlas", "customer-brief"]>, "many">, ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[], ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[]>, ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[], ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[]>>;
144
114
  }, "strict", z.ZodTypeAny, {
145
115
  title: string;
146
116
  expectedRevision: number;
@@ -170,7 +140,13 @@ export declare const updateToolSchema: z.ZodObject<{
170
140
  }[] | undefined;
171
141
  supersedesPaths?: string[] | undefined;
172
142
  previewIds?: string[] | undefined;
173
- libraries?: ("echarts" | "three")[] | undefined;
143
+ libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
144
+ removals?: {
145
+ bindingIds: string[];
146
+ controlIds: string[];
147
+ viewIds: string[];
148
+ htmlElementIds: string[];
149
+ } | undefined;
174
150
  htmlPath?: string | undefined;
175
151
  }, {
176
152
  title: string;
@@ -182,12 +158,28 @@ export declare const updateToolSchema: z.ZodObject<{
182
158
  tables?: unknown;
183
159
  supersedesPaths?: string[] | undefined;
184
160
  previewIds?: unknown;
185
- libraries?: ("echarts" | "three")[] | undefined;
161
+ libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
162
+ removals?: {
163
+ bindingIds?: string[] | undefined;
164
+ controlIds?: string[] | undefined;
165
+ viewIds?: string[] | undefined;
166
+ htmlElementIds?: string[] | undefined;
167
+ } | undefined;
186
168
  htmlPath?: string | undefined;
187
169
  }>;
188
- export declare const EDITING_GUIDANCE = "Opening or reading a dashboard does not modify it. 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; 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 and dependency locks unless requested. 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.";
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.";
189
171
  /** Run-local read receipts carry planning versions; authorization and CAS remain in the domain service. */
190
- export declare function createEditingTools(service: DashboardService, scope: XpertResolvedViewHostContext, context: IAgentMiddlewareContext, resolvePreviews: (ids: string[]) => AnalyticsBinding[], validateFinal: (manifest: DashboardManifest, requirePreviews: boolean) => void, onOpen?: (path: string, artifactId: string) => void): (import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>, {}, {}, string> | import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
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<{
173
+ page: z.ZodDefault<z.ZodNumber>;
174
+ }, "strict", z.ZodTypeAny, {
175
+ page: number;
176
+ }, {
177
+ page?: number | undefined;
178
+ }>, {
179
+ page: number;
180
+ }, {
181
+ page?: number | undefined;
182
+ }, string> | import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
191
183
  editId: z.ZodString;
192
184
  versionId: z.ZodOptional<z.ZodString>;
193
185
  offset: z.ZodDefault<z.ZodNumber>;
@@ -225,7 +217,6 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
225
217
  }, {
226
218
  artifactId?: string | undefined;
227
219
  }, string> | import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
228
- supersedesPaths: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
229
220
  controls: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
230
221
  controlId: z.ZodString;
231
222
  type: z.ZodEnum<["string", "number", "boolean", "date"]>;
@@ -306,14 +297,31 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
306
297
  datasetId: string;
307
298
  fields: string[];
308
299
  }[], unknown>>;
300
+ supersedesPaths: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
309
301
  previewIds: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], unknown>>;
310
302
  } & {
303
+ removals: z.ZodOptional<z.ZodObject<{
304
+ bindingIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
305
+ controlIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
306
+ viewIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
307
+ htmlElementIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
308
+ }, "strict", z.ZodTypeAny, {
309
+ bindingIds: string[];
310
+ controlIds: string[];
311
+ viewIds: string[];
312
+ htmlElementIds: string[];
313
+ }, {
314
+ bindingIds?: string[] | undefined;
315
+ controlIds?: string[] | undefined;
316
+ viewIds?: string[] | undefined;
317
+ htmlElementIds?: string[] | undefined;
318
+ }>>;
311
319
  title: z.ZodString;
312
320
  editId: z.ZodString;
313
321
  expectedRevision: z.ZodNumber;
314
322
  expectedCurrentVersionId: z.ZodNullable<z.ZodString>;
315
323
  htmlPath: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>>;
316
- libraries: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEnum<["echarts", "three"]>, "many">, ("echarts" | "three")[], ("echarts" | "three")[]>>;
324
+ libraries: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["echarts", "three", "trend-workspace", "profit-atlas", "customer-brief"]>, "many">, ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[], ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[]>, ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[], ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[]>>;
317
325
  }, "strict", z.ZodTypeAny, {
318
326
  title: string;
319
327
  expectedRevision: number;
@@ -343,7 +351,13 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
343
351
  }[] | undefined;
344
352
  supersedesPaths?: string[] | undefined;
345
353
  previewIds?: string[] | undefined;
346
- libraries?: ("echarts" | "three")[] | undefined;
354
+ libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
355
+ removals?: {
356
+ bindingIds: string[];
357
+ controlIds: string[];
358
+ viewIds: string[];
359
+ htmlElementIds: string[];
360
+ } | undefined;
347
361
  htmlPath?: string | undefined;
348
362
  }, {
349
363
  title: string;
@@ -355,7 +369,13 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
355
369
  tables?: unknown;
356
370
  supersedesPaths?: string[] | undefined;
357
371
  previewIds?: unknown;
358
- libraries?: ("echarts" | "three")[] | undefined;
372
+ libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
373
+ removals?: {
374
+ bindingIds?: string[] | undefined;
375
+ controlIds?: string[] | undefined;
376
+ viewIds?: string[] | undefined;
377
+ htmlElementIds?: string[] | undefined;
378
+ } | undefined;
359
379
  htmlPath?: string | undefined;
360
380
  }>, {
361
381
  title: string;
@@ -386,7 +406,13 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
386
406
  }[] | undefined;
387
407
  supersedesPaths?: string[] | undefined;
388
408
  previewIds?: string[] | undefined;
389
- libraries?: ("echarts" | "three")[] | undefined;
409
+ libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
410
+ removals?: {
411
+ bindingIds: string[];
412
+ controlIds: string[];
413
+ viewIds: string[];
414
+ htmlElementIds: string[];
415
+ } | undefined;
390
416
  htmlPath?: string | undefined;
391
417
  }, {
392
418
  title: string;
@@ -398,6 +424,12 @@ export declare function createEditingTools(service: DashboardService, scope: Xpe
398
424
  tables?: unknown;
399
425
  supersedesPaths?: string[] | undefined;
400
426
  previewIds?: unknown;
401
- libraries?: ("echarts" | "three")[] | undefined;
427
+ libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
428
+ removals?: {
429
+ bindingIds?: string[] | undefined;
430
+ controlIds?: string[] | undefined;
431
+ viewIds?: string[] | undefined;
432
+ htmlElementIds?: string[] | undefined;
433
+ } | undefined;
402
434
  htmlPath?: string | undefined;
403
435
  }, string>)[];
@@ -11,36 +11,39 @@ const agent_schema_1 = require("./agent.schema");
11
11
  const dashboard_schema_1 = require("./dashboard.schema");
12
12
  const document_libraries_1 = require("./document-libraries");
13
13
  const resource_card_1 = require("./resource-card");
14
- exports.dashboardSelectionSchema = v3_1.z.object({ schemaVersion: v3_1.z.literal(1), artifactId: v3_1.z.string().uuid(), versionId: v3_1.z.string().uuid().optional(), draftRevision: v3_1.z.number().int().positive().optional() }).strict();
15
- exports.dashboardContextSchema = v3_1.z.object({ live_dashboard: exports.dashboardSelectionSchema.nullable().optional() });
16
- const configSchema = v3_1.z.object({ context: exports.dashboardContextSchema.optional(), configurable: v3_1.z.object({ context: exports.dashboardContextSchema.optional() }).optional() });
14
+ const editing_session_1 = require("./editing-session");
15
+ const editing_patch_1 = require("./editing-patch");
16
+ const editing_feedback_1 = require("./editing-feedback");
17
+ var editing_session_2 = require("./editing-session");
18
+ Object.defineProperty(exports, "dashboardSelectionSchema", { enumerable: true, get: function () { return editing_session_2.dashboardSelectionSchema; } });
19
+ Object.defineProperty(exports, "dashboardContextSchema", { enumerable: true, get: function () { return editing_session_2.dashboardContextSchema; } });
17
20
  const targetSchema = v3_1.z.object({ artifactId: v3_1.z.string().uuid().optional().describe('From dashboard_list or a saved receipt. Omit only for the current Workbench selection.'),
18
21
  versionId: v3_1.z.string().uuid().optional().describe('Exact historical version when requested. Otherwise open the selected or current version.') }).strict();
19
- exports.updateToolSchema = agent_schema_1.createToolSchema.partial().extend({ title: agent_schema_1.createToolSchema.shape.title.describe('Required saved Artifact title. Use the requested new title when renaming; otherwise copy the current title from dashboard_open. Submit it together with htmlPath when changing the page.'), editId: v3_1.z.string().uuid().describe("Stable Artifact ID returned by dashboard_open"), expectedRevision: v3_1.z.number().int().nonnegative().describe('Copy the current draft revision returned by dashboard_open.'), expectedCurrentVersionId: v3_1.z.string().uuid({ message: 'Copy the exact UUID from dashboard_open, or use JSON null when no formal version exists. Never use the strings None, null or an empty string.' }).nullable().describe('Copy dashboard_open.expectedCurrentVersionId exactly: UUID or actual JSON null. Never the strings None/null. Keep all requested changes (including title) when correcting another field.'), htmlPath: agent_schema_1.htmlPathSchema.optional(),
22
+ exports.updateToolSchema = agent_schema_1.createToolSchema.omit({ creationIntent: true }).partial().extend({ removals: editing_patch_1.removalsSchema, title: agent_schema_1.createToolSchema.shape.title.describe('Required saved Artifact title. Use the requested new title when renaming; otherwise copy the current title from dashboard_open. Submit it together with htmlPath when changing the page.'), editId: v3_1.z.string().uuid().describe("Stable Artifact ID returned by dashboard_open"), expectedRevision: v3_1.z.number().int().nonnegative().describe('Copy the current draft revision returned by dashboard_open.'), expectedCurrentVersionId: v3_1.z.string().uuid({ message: 'Copy the exact UUID from dashboard_open, or use JSON null when no formal version exists. Never use the strings None, null or an empty string.' }).nullable().describe('Copy dashboard_open.expectedCurrentVersionId exactly: UUID or actual JSON null. Never the strings None/null. Keep all requested changes (including title) when correcting another field.'), htmlPath: agent_schema_1.htmlPathSchema.optional(),
20
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();
21
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),
22
25
  length: v3_1.z.number().int().min(1).max(24000).default(16000) }).strict();
23
- exports.EDITING_GUIDANCE = `Opening or reading a dashboard does not modify it. 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; 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 and dependency locks unless requested. 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. 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.`;
24
27
  /** Run-local read receipts carry planning versions; authorization and CAS remain in the domain service. */
25
- function createEditingTools(service, scope, context, resolvePreviews, validateFinal, onOpen = () => undefined) {
28
+ function createEditingTools(service, scope, context, resolvePreviews, validateFinal, onOpen = () => undefined, currentTarget = editing_session_1.selectionFromConfig) {
26
29
  const target = (input, config) => {
27
- const parsed = configSchema.safeParse(config);
28
- // LangGraph can provide a top-level execution context alongside the request context.
29
- // An unrelated (or schema-stripped empty) execution context must not mask the selection.
30
- const selected = parsed.success ? parsed.data.context?.live_dashboard !== undefined
31
- ? parsed.data.context.live_dashboard : parsed.data.configurable?.context?.live_dashboard : undefined;
30
+ const selected = currentTarget(config);
32
31
  if (input.artifactId)
33
32
  return { artifactId: input.artifactId, versionId: input.versionId };
34
33
  if (!selected)
35
- throw new Error('DASHBOARD_TARGET_REQUIRED: select a dashboard in Workbench or use dashboard_list and provide its artifactId');
36
- return { artifactId: selected.artifactId, versionId: input.versionId };
34
+ return null;
35
+ return { artifactId: selected.artifactId,
36
+ versionId: input.versionId ?? (selected.draftRevision === undefined ? selected.versionId : undefined) };
37
37
  };
38
38
  return [
39
- (0, tools_1.tool)(async () => JSON.stringify({ dashboards: await service.list(scope) }), { name: 'dashboard_list',
40
- description: 'List saved dashboards in the current authorized host. Use returned IDs to open one; do not infer a target from recency.',
41
- schema: v3_1.z.object({}).strict(), verboseParsingErrors: true, metadata: { toolName: { en_US: 'List saved dashboards', zh_Hans: '查找已保存看板' } } }),
39
+ (0, tools_1.tool)(async ({ page }) => { const result = await service.listPage(scope, page, 50); return JSON.stringify({ dashboards: result.items, page: result.page, hasMore: result.hasMore }); }, { name: 'dashboard_list',
40
+ description: 'List saved dashboards in the current authorized host. Follow page and hasMore for the full list. Use returned IDs to open one; do not infer a target from recency.',
41
+ schema: v3_1.z.object({ page: v3_1.z.number().int().positive().default(1) }).strict(), verboseParsingErrors: true, metadata: { toolName: { en_US: 'List saved dashboards', zh_Hans: '查找已保存看板' } } }),
42
42
  (0, tools_1.tool)(async (input, config) => {
43
- const resolved = target(input, config), saved = await service.open(scope, resolved.artifactId, resolved.versionId);
43
+ const resolved = target(input, config);
44
+ if (!resolved)
45
+ return JSON.stringify((0, editing_feedback_1.dashboardSelectionRequired)(config));
46
+ const saved = await service.open(scope, resolved.artifactId, resolved.versionId);
44
47
  const editId = saved.artifactId;
45
48
  const { presentation, schema, id, ...definition } = saved.manifest;
46
49
  let htmlPath;
@@ -58,7 +61,7 @@ function createEditingTools(service, scope, context, resolvePreviews, validateFi
58
61
  : { state: 'published', versionNumber: saved.versionNumber ?? 0, versionId: resolved.versionId }) }, config);
59
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,
60
63
  ...definition, presentation: presentation ? { type: 'html', characters: presentation.html.length, dependencies: presentation.dependencies ?? [] } : { type: 'standard' },
61
- ...(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, 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 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.' } : {}) });
62
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.',
63
66
  schema: targetSchema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Read dashboard for editing', zh_Hans: '读取看板以继续修改' } } }),
64
67
  (0, tools_1.tool)(async (input) => {
@@ -75,13 +78,21 @@ function createEditingTools(service, scope, context, resolvePreviews, validateFi
75
78
  schema: readHtmlSchema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Read dashboard HTML', zh_Hans: '读取看板页面源码' } } }),
76
79
  (0, tools_1.tool)(async (input, config) => {
77
80
  const resolved = target(input, config);
81
+ if (!resolved)
82
+ return JSON.stringify((0, editing_feedback_1.dashboardSelectionRequired)(config));
78
83
  return JSON.stringify({ artifactId: resolved.artifactId, versions: await service.history(scope, resolved.artifactId) });
79
84
  }, { name: 'dashboard_history', description: 'List immutable versions of an authorized dashboard. Open a returned version to inspect it; history does not change the current version.',
80
85
  schema: targetSchema.omit({ versionId: true }), verboseParsingErrors: true, metadata: { toolName: { en_US: 'Read dashboard history', zh_Hans: '查看看板版本历史' } } }),
81
86
  (0, tools_1.tool)(async (input, config) => {
82
87
  const saved = await service.open(scope, input.editId);
83
- const { editId, expectedRevision, expectedCurrentVersionId, htmlPath, previewIds, libraries, ...changes } = input;
84
- const bindings = previewIds ? resolvePreviews(previewIds) : saved.manifest.bindings;
88
+ const { editId, expectedRevision, expectedCurrentVersionId, htmlPath, previewIds, libraries, removals, ...changes } = input;
89
+ const changedBindings = previewIds ? resolvePreviews(previewIds) : undefined;
90
+ const bindings = (0, editing_patch_1.upsertComponents)(saved.manifest.bindings, changedBindings, item => item.id, removals?.bindingIds);
91
+ const controls = (0, editing_patch_1.upsertComponents)(saved.manifest.controls, changes.controls, item => item.controlId, removals?.controlIds);
92
+ if (removals?.viewIds.some(id => ![...saved.manifest.charts, ...saved.manifest.tables].some(view => view.id === id)))
93
+ throw new Error('DASHBOARD_REMOVAL_INVALID: copy existing view IDs');
94
+ 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)));
95
+ const tables = (0, editing_patch_1.upsertComponents)(saved.manifest.tables, changes.tables, item => item.id, removals?.viewIds.filter(id => saved.manifest.tables.some(item => item.id === id)));
85
96
  let presentation = saved.manifest.presentation;
86
97
  let sourceFile;
87
98
  if (htmlPath) {
@@ -101,14 +112,15 @@ function createEditingTools(service, scope, context, resolvePreviews, validateFi
101
112
  throw new Error('DASHBOARD_HTML_REQUIRED');
102
113
  presentation = { ...presentation, dependencies: await (0, document_libraries_1.libraryLocks)(libraries) };
103
114
  }
104
- const manifest = dashboard_schema_1.dashboardSchema.parse({ ...saved.manifest, ...changes, bindings,
105
- ...(presentation ? { presentation, charts: changes.charts ?? [], tables: changes.tables ?? [] } : {}) });
106
- validateFinal(manifest, previewIds !== undefined);
115
+ (0, editing_patch_1.assertHtmlPreserved)(saved.manifest.presentation, presentation, removals?.htmlElementIds);
116
+ const manifest = dashboard_schema_1.dashboardSchema.parse({ ...saved.manifest, ...changes, bindings, controls, charts, tables,
117
+ ...(presentation ? { presentation } : {}) });
118
+ validateFinal(manifest, previewIds !== undefined, changedBindings?.map(item => item.id));
107
119
  const { schema, id, ...update } = manifest;
108
120
  const result = await service.update(scope, editId, expectedRevision, update, expectedCurrentVersionId);
109
121
  const resourceCard = await (0, resource_card_1.emitDashboardCard)(scope, { ...result, state: 'draft', revision: result.draftRevision }, config);
110
122
  return JSON.stringify({ dashboard: result, resourceCard, ...(sourceFile ? { sourceFile } : {}) });
111
- }, { name: 'dashboard_update', description: 'Update the opened dashboard in place, preserving its Artifact ID and version history. Supply stable editId and expectedRevision from dashboard_open, the explicit current or requested title, plus only other changed fields. Saves a persistent draft; does not publish. For an HTML rename, send title and htmlPath together; HTML headings do not rename the Artifact. htmlPath replaces the page; omitted previewIds preserves bindings, while supplied previewIds replaces the complete set with successful fresh previews. Conflicting edits fail instead of overwriting.',
123
+ }, { name: 'dashboard_update', description: 'Update the opened dashboard in place, preserving its Artifact ID and version history. Supply stable editId and expectedRevision from dashboard_open, the explicit current or requested title, plus only other changed fields. Saves a persistent draft; does not publish. For an HTML rename, send title and htmlPath together; HTML headings do not rename the Artifact. htmlPath replaces the page; omitted previewIds preserves bindings, while supplied previewIds upserts changed bindings by stable ID. Controls/charts/tables also upsert by ID. Use removals only for explicitly requested deletions. Preserve HTML IDs unless their removal is requested. Conflicting edits fail instead of overwriting.',
112
124
  schema: exports.updateToolSchema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Save dashboard changes', zh_Hans: '保存看板修改' } } })
113
125
  ];
114
126
  }
@@ -1 +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 and the allowed HTTPS origins for online scripts, stylesheets and fonts. Tailwind CDN is supported through script src; pin a version when possible. Online resource failures must be repaired before saving. Do not add online URLs to the packaged libraries array; all data access remains declarative Binding queries through window.xpertLiveArtifact. 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.";
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.";
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HTML_DASHBOARD_GUIDANCE = void 0;
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 and the allowed HTTPS origins for online scripts, stylesheets and fonts. Tailwind CDN is supported through script src; pin a version when possible. Online resource failures must be repaired before saving. Do not add online URLs to the packaged libraries array; all data access remains declarative Binding queries through window.xpertLiveArtifact. 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.`;
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.`;