@xpert-ai/plugin-live-dashboard 0.3.1 → 0.4.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.
- package/.xpertai-plugin/plugin.json +10 -2
- package/README.md +6 -0
- package/assets/branding/cover-v1.prompt.txt +27 -0
- package/assets/branding/cover-v1.webp +0 -0
- package/assets/previews/customer-brief.png +0 -0
- package/assets/previews/profit-atlas.png +0 -0
- package/assets/previews/trend-workspace.png +0 -0
- package/dist/index.js +6 -3
- package/dist/lib/agent.schema.d.ts +43 -37
- package/dist/lib/agent.schema.js +2 -1
- package/dist/lib/app-config.d.ts +62 -0
- package/dist/lib/app-config.js +38 -0
- package/dist/lib/artifact-type.provider.d.ts +15 -0
- package/dist/lib/artifact-type.provider.js +78 -0
- package/dist/lib/assistant-template.d.ts +1 -2
- package/dist/lib/assistant-template.js +3 -52
- package/dist/lib/content.provider.js +13 -5
- package/dist/lib/dashboard-navigation.d.ts +58 -14
- package/dist/lib/dashboard-navigation.js +11 -10
- package/dist/lib/dashboard-view.schema.d.ts +197 -46
- package/dist/lib/dashboard-view.schema.js +8 -1
- package/dist/lib/dashboard.service.d.ts +39 -2
- package/dist/lib/dashboard.service.js +52 -28
- package/dist/lib/document-libraries.d.ts +1 -1
- package/dist/lib/document-libraries.js +3 -2
- package/dist/lib/document-network.d.ts +1 -1
- package/dist/lib/document-network.js +2 -6
- package/dist/lib/editing-feedback.d.ts +5 -0
- package/dist/lib/editing-feedback.js +19 -0
- package/dist/lib/editing-patch.d.ts +22 -0
- package/dist/lib/editing-patch.js +46 -0
- package/dist/lib/editing-session.d.ts +167 -0
- package/dist/lib/editing-session.js +53 -0
- package/dist/lib/editing.d.ts +92 -60
- package/dist/lib/editing.js +36 -24
- package/dist/lib/html-guidance.d.ts +1 -1
- package/dist/lib/html-guidance.js +1 -1
- package/dist/lib/middleware.js +42 -18
- package/dist/lib/monitor.d.ts +70 -0
- package/dist/lib/monitor.js +101 -0
- package/dist/lib/plugin.js +4 -1
- package/dist/lib/project.d.ts +106 -0
- package/dist/lib/project.js +17 -0
- package/dist/lib/projects.schema.d.ts +49 -0
- package/dist/lib/projects.schema.js +7 -0
- package/dist/lib/projects.service.d.ts +23 -0
- package/dist/lib/projects.service.js +65 -0
- package/dist/lib/resource-card.js +1 -1
- package/dist/lib/runtime-context.d.ts +3 -0
- package/dist/lib/runtime-context.js +13 -0
- package/dist/lib/save-evidence.d.ts +1 -1
- package/dist/lib/templates.d.ts +2 -0
- package/dist/lib/templates.js +55 -0
- package/dist/lib/view.provider.d.ts +97 -7
- package/dist/lib/view.provider.js +39 -10
- package/dist/libraries/TREND-WORKSPACE-ICONS-LICENSE.txt +43 -0
- package/dist/libraries/catalog.json +1 -1
- package/dist/remote/app.css +1 -1
- package/dist/remote/app.js +33 -33
- package/dist/remote/build-manifest.json +115 -32
- package/dist/sandbox-actions/action.json +1 -1
- package/dist/sandbox-actions/bundle/host.js +2 -2
- package/dist/sandbox-actions/bundle/resource-cache.mjs +2 -1
- package/dist/sandbox-actions/bundle/validate.mjs +1 -1
- package/docs/docs.json +7 -0
- package/docs/frontend-libraries.mdx +12 -4
- package/docs/html-mode.md +3 -3
- package/docs/quick-start-acceptance.mdx +50 -0
- package/docs/quick-start.mdx +64 -0
- package/docs/superstore.mdx +38 -0
- package/docs/team-sharing.mdx +6 -2
- package/docs/trend-workspace-acceptance.mdx +43 -0
- package/docs/trend-workspace.mdx +30 -0
- package/docs/verification.mdx +4 -2
- package/docs/visual-styles-acceptance.mdx +40 -0
- package/docs/visual-styles.mdx +46 -0
- package/package.json +23 -17
- package/skills/live-dashboard/SKILL.md +27 -3
- package/skills/live-dashboard/examples/README.md +25 -0
- package/skills/live-dashboard/examples/catalog.json +79 -0
- package/skills/live-dashboard/examples/production-quality/README.md +25 -0
- package/skills/live-dashboard/examples/production-quality/dashboard.html +129 -0
- package/skills/live-dashboard/examples/production-quality/definition.json +67 -0
- package/skills/live-dashboard/examples/production-quality/demo.csv +7 -0
- package/skills/live-dashboard/examples/production-quality/demo.json +44 -0
- package/skills/live-dashboard/examples/production-quality/expected.json +26 -0
- package/skills/live-dashboard/examples/production-quality/preview.png +0 -0
- package/skills/live-dashboard/examples/production-quality/query.json +53 -0
- package/skills/live-dashboard/examples/regional-sales/README.md +25 -0
- package/skills/live-dashboard/examples/regional-sales/dashboard-create.json +35 -0
- package/skills/live-dashboard/examples/regional-sales/definition.json +35 -0
- package/skills/live-dashboard/examples/regional-sales/demo.csv +5 -0
- package/skills/live-dashboard/examples/regional-sales/demo.json +18 -0
- package/skills/live-dashboard/examples/regional-sales/expected.json +19 -0
- package/skills/live-dashboard/examples/regional-sales/preview.png +0 -0
- package/skills/live-dashboard/examples/regional-sales/query.json +45 -0
- package/skills/live-dashboard/examples/sales-overview/README.md +25 -0
- package/skills/live-dashboard/examples/sales-overview/dashboard.html +129 -0
- package/skills/live-dashboard/examples/sales-overview/definition.json +57 -0
- package/skills/live-dashboard/examples/sales-overview/demo.csv +7 -0
- package/skills/live-dashboard/examples/sales-overview/demo.json +38 -0
- package/skills/live-dashboard/examples/sales-overview/expected.json +22 -0
- package/skills/live-dashboard/examples/sales-overview/preview.png +0 -0
- package/skills/live-dashboard/examples/sales-overview/query.json +52 -0
- package/skills/live-dashboard/examples/superstore/README.md +64 -0
- package/skills/live-dashboard/examples/superstore/THIRD_PARTY_LICENSE.txt +207 -0
- package/skills/live-dashboard/examples/superstore/build_data.py +155 -0
- package/skills/live-dashboard/examples/superstore/build_pages.py +129 -0
- package/skills/live-dashboard/examples/superstore/checks.json +104 -0
- package/skills/live-dashboard/examples/superstore/customers-mobile-dark.png +0 -0
- package/skills/live-dashboard/examples/superstore/customers-select.png +0 -0
- package/skills/live-dashboard/examples/superstore/customers.html +316 -0
- package/skills/live-dashboard/examples/superstore/customers.png +0 -0
- package/skills/live-dashboard/examples/superstore/customers.queries.json +512 -0
- package/skills/live-dashboard/examples/superstore/expected.json +4069 -0
- package/skills/live-dashboard/examples/superstore/import.json +200 -0
- package/skills/live-dashboard/examples/superstore/orders.csv +10195 -0
- package/skills/live-dashboard/examples/superstore/overview-mobile-dark.png +0 -0
- package/skills/live-dashboard/examples/superstore/overview-select.png +0 -0
- package/skills/live-dashboard/examples/superstore/overview.html +310 -0
- package/skills/live-dashboard/examples/superstore/overview.png +0 -0
- package/skills/live-dashboard/examples/superstore/overview.queries.json +636 -0
- package/skills/live-dashboard/examples/superstore/page.js +109 -0
- package/skills/live-dashboard/examples/superstore/profitability-mobile-dark.png +0 -0
- package/skills/live-dashboard/examples/superstore/profitability-select.png +0 -0
- package/skills/live-dashboard/examples/superstore/profitability.html +307 -0
- package/skills/live-dashboard/examples/superstore/profitability.png +0 -0
- package/skills/live-dashboard/examples/superstore/profitability.queries.json +334 -0
- package/skills/live-dashboard/examples/superstore/provenance.json +24 -0
- package/skills/live-dashboard/examples/superstore/semantic-model.json +220 -0
- package/skills/live-dashboard/examples/superstore/test_data.py +62 -0
- package/skills/live-dashboard/references/html-runtime.md +1 -1
- package/skills/live-dashboard/themes/README.md +50 -0
- package/skills/live-dashboard/themes/customer-brief/README.md +47 -0
- package/skills/live-dashboard/themes/customer-brief/charts.js +17 -0
- package/skills/live-dashboard/themes/customer-brief/layout.html +22 -0
- package/skills/live-dashboard/themes/customer-brief/theme.css +108 -0
- package/skills/live-dashboard/themes/profit-atlas/README.md +43 -0
- package/skills/live-dashboard/themes/profit-atlas/charts.js +30 -0
- package/skills/live-dashboard/themes/profit-atlas/layout.html +19 -0
- package/skills/live-dashboard/themes/profit-atlas/theme.css +75 -0
- package/skills/live-dashboard/themes/trend-workspace/ICON_LICENSE.txt +43 -0
- package/skills/live-dashboard/themes/trend-workspace/README.md +144 -0
- package/skills/live-dashboard/themes/trend-workspace/charts.js +60 -0
- package/skills/live-dashboard/themes/trend-workspace/icons.js +11 -0
- package/skills/live-dashboard/themes/trend-workspace/layout.html +45 -0
- package/skills/live-dashboard/themes/trend-workspace/select.js +127 -0
- package/skills/live-dashboard/themes/trend-workspace/theme.css +137 -0
package/dist/lib/editing.d.ts
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
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
|
|
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
|
|
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>)[];
|
package/dist/lib/editing.js
CHANGED
|
@@ -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
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
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
|
|
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
|
|
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
|
-
|
|
36
|
-
return { artifactId: selected.artifactId,
|
|
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:
|
|
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)
|
|
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,
|
|
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
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
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
|
|
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
|
|
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.`;
|
package/dist/lib/middleware.js
CHANGED
|
@@ -10,9 +10,11 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.DashboardMiddleware = exports.DASHBOARD_GUIDANCE = void 0;
|
|
13
|
+
const runtime_context_1 = require("./runtime-context");
|
|
13
14
|
const definition_tools_1 = require("./definition-tools");
|
|
14
15
|
const analytics_source_1 = require("./analytics-source");
|
|
15
16
|
const analytics_1 = require("@xpert-ai/plugin-sdk/analytics");
|
|
17
|
+
const langgraph_1 = require("@langchain/langgraph");
|
|
16
18
|
const messages_1 = require("@langchain/core/messages");
|
|
17
19
|
const tools_1 = require("@langchain/core/tools");
|
|
18
20
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -27,6 +29,7 @@ const dashboard_service_1 = require("./dashboard.service");
|
|
|
27
29
|
const dashboard_schema_1 = require("./dashboard.schema");
|
|
28
30
|
const view_provider_1 = require("./view.provider");
|
|
29
31
|
const editing_1 = require("./editing");
|
|
32
|
+
const editing_session_1 = require("./editing-session");
|
|
30
33
|
const dashboard_receipt_1 = require("./dashboard-receipt");
|
|
31
34
|
const filter_evidence_1 = require("./filter-evidence");
|
|
32
35
|
const save_evidence_1 = require("./save-evidence");
|
|
@@ -34,7 +37,8 @@ const resource_card_1 = require("./resource-card");
|
|
|
34
37
|
const dashboard_icon_1 = require("./dashboard-icon");
|
|
35
38
|
const preview_retry_1 = require("./preview-retry");
|
|
36
39
|
const prompt_workflows_1 = require("./prompt-workflows");
|
|
37
|
-
const middlewareOptionsSchema = v3_1.z.object({ allowedFinalProviders: v3_1.z.array(v3_1.z.string().min(1)).min(1).max(20).optional()
|
|
40
|
+
const middlewareOptionsSchema = v3_1.z.object({ allowedFinalProviders: v3_1.z.array(v3_1.z.string().min(1)).min(1).max(20).optional(),
|
|
41
|
+
maxModelCalls: v3_1.z.number().int().min(1).max(64).default(24) }).strict().default({});
|
|
38
42
|
const providerOptionSchema = {
|
|
39
43
|
type: 'string',
|
|
40
44
|
'x-ui': { component: 'remoteSelect', selectUrl: '/api/live-dashboard/provider-options' }
|
|
@@ -49,6 +53,9 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
49
53
|
slashCommands: prompt_workflows_1.dashboardPromptWorkflows,
|
|
50
54
|
// Tools inherit this self-contained icon through the platform middleware metadata.
|
|
51
55
|
icon: dashboard_icon_1.dashboardIcon, features: [view_provider_1.FEATURE], configSchema: { type: 'object', properties: {
|
|
56
|
+
maxModelCalls: { type: 'integer', minimum: 1, maximum: 64, default: 24,
|
|
57
|
+
title: { en_US: 'Model call limit', zh_Hans: '模型调用上限' },
|
|
58
|
+
description: { en_US: 'Bounded per-run budget, including recipe reads and source setup. Save validation remains required.', zh_Hans: '每次执行的调用预算,包含配方读取和数据源准备;保存校验仍然必须通过。' } },
|
|
52
59
|
allowedFinalProviders: { type: 'array', minItems: 1, maxItems: 20, items: providerOptionSchema, title: { en_US: 'Allowed final dashboard providers', zh_Hans: '最终看板允许的数据源类型' },
|
|
53
60
|
description: { en_US: 'Choose at least one provider from sources you can access when setting this policy. Existing unavailable IDs are retained. Upstream previews remain available.', zh_Hans: '配置此限制时至少选择一种当前可访问数据源的 Provider;暂不可用的已有值会保留,不影响上游来源预览。' } }
|
|
54
61
|
}, additionalProperties: false }
|
|
@@ -58,10 +65,8 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
58
65
|
const options = middlewareOptionsSchema.parse(_options);
|
|
59
66
|
if (!context.xpertId)
|
|
60
67
|
throw new Error('DASHBOARD_ASSISTANT_REQUIRED');
|
|
61
|
-
const scope =
|
|
62
|
-
|
|
63
|
-
userId: context.userId ?? plugin_sdk_1.RequestContext.currentUserId(), hostType: context.projectId ? 'project' : 'agent', hostId: context.projectId ?? context.xpertId, slots: []
|
|
64
|
-
};
|
|
68
|
+
const scope = (0, runtime_context_1.dashboardRuntimeContext)(context);
|
|
69
|
+
const editing = (0, editing_session_1.editingSession)({ ...context, tenantId: scope.tenantId, organizationId: scope.organizationId, userId: scope.userId });
|
|
65
70
|
// Evidence belongs to this run and actor, never a process-wide cache of business data.
|
|
66
71
|
const discovered = new Map(), previews = new Map();
|
|
67
72
|
const discovering = new Map();
|
|
@@ -114,13 +119,13 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
114
119
|
throw new Error('DASHBOARD_PREVIEW_REQUIRED: use a previewId returned in this run');
|
|
115
120
|
return binding;
|
|
116
121
|
});
|
|
117
|
-
const validateFinal = (manifest, requirePreviews) => {
|
|
122
|
+
const validateFinal = (manifest, requirePreviews, changedBindingIds) => {
|
|
118
123
|
const allowedProviders = options.allowedFinalProviders;
|
|
119
124
|
if (allowedProviders && manifest.bindings.some(binding => !allowedProviders.includes(binding.providerId)))
|
|
120
125
|
throw new Error(`DASHBOARD_PROVIDER_REQUIRED: final bindings must use ${allowedProviders.join(', ')}`);
|
|
121
126
|
if (requirePreviews) {
|
|
122
127
|
const controls = Object.fromEntries(manifest.controls.filter(item => item.defaultValue !== undefined).map(item => [item.controlId, item.defaultValue ?? null]));
|
|
123
|
-
for (const binding of manifest.bindings) {
|
|
128
|
+
for (const binding of manifest.bindings.filter(binding => !changedBindingIds || changedBindingIds.includes(binding.id))) {
|
|
124
129
|
const previewId = previewKey(binding, controls);
|
|
125
130
|
if (!previews.has(previewId))
|
|
126
131
|
throw new Error('DASHBOARD_PREVIEW_REQUIRED: preview the exact binding and default controls before saving');
|
|
@@ -129,13 +134,16 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
129
134
|
}
|
|
130
135
|
};
|
|
131
136
|
const save = async (input, config, html, dependencies = []) => {
|
|
132
|
-
const { previewIds, supersedesPaths, ...definition } = input;
|
|
137
|
+
const { previewIds, supersedesPaths, creationIntent, ...definition } = input;
|
|
133
138
|
const bindings = resolvePreviews(previewIds);
|
|
134
139
|
const manifest = dashboard_schema_1.dashboardSchema.parse({ ...definition, bindings, schema: 'xpert.live-dashboard', id: (0, node_crypto_1.randomUUID)(),
|
|
135
140
|
...(html ? { presentation: { type: 'html', html, ...(dependencies.length ? { dependencies } : {}) } } : {}) });
|
|
136
141
|
validateFinal(manifest, true);
|
|
137
142
|
const key = hash({ input: { ...definition, previewIds }, html, dependencies });
|
|
138
143
|
const previous = created.get(key);
|
|
144
|
+
const active = editing.resolve(config);
|
|
145
|
+
if (active && !creationIntent && (!previous || previous.receipt.artifactId !== active.artifactId))
|
|
146
|
+
throw new Error('DASHBOARD_EDIT_TARGET_ACTIVE: use dashboard_open/update for the active dashboard. Creating a new Artifact requires an explicit user request and creationIntent=new or copy.');
|
|
139
147
|
if (previous) {
|
|
140
148
|
const receipt = await this.service.save(scope, previous.manifest, previous.receipt.baseVersionId, previous.receipt.draftRevision);
|
|
141
149
|
created.set(key, { manifest: previous.manifest, receipt });
|
|
@@ -143,7 +151,7 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
143
151
|
return JSON.stringify({ dashboard: receipt, resourceCard });
|
|
144
152
|
}
|
|
145
153
|
const sameTitle = [...created.values()].find(item => item.manifest.title === manifest.title);
|
|
146
|
-
if (sameTitle)
|
|
154
|
+
if (sameTitle && !creationIntent)
|
|
147
155
|
throw new Error(`DASHBOARD_ALREADY_CREATED: this run already saved this dashboard. Use dashboard_open with artifactId ${sameTitle.receipt.artifactId}, then dashboard_update with fresh previewIds for data changes; preserve the Artifact instead of creating another one.`);
|
|
148
156
|
const result = await this.service.save(scope, manifest, null);
|
|
149
157
|
created.set(key, { manifest, receipt: result });
|
|
@@ -158,7 +166,9 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
158
166
|
});
|
|
159
167
|
const previewRetries = (0, preview_retry_1.createPreviewRetryGuard)();
|
|
160
168
|
let modelCalls = 0;
|
|
161
|
-
return { name: 'LiveDashboard', contextSchema: editing_1.dashboardContextSchema,
|
|
169
|
+
return { name: 'LiveDashboard', contextSchema: editing_1.dashboardContextSchema, stateSchema: editing_session_1.dashboardStateSchema,
|
|
170
|
+
// Platform execution scope and request context occupy different runtime fields.
|
|
171
|
+
beforeAgent: (state, runtime) => editing.restore(state, { live_dashboard: (0, editing_session_1.selectionFromConfig)(runtime) }),
|
|
162
172
|
wrapToolCall: async (request, handler) => {
|
|
163
173
|
const name = request.toolCall.name;
|
|
164
174
|
const args = request.toolCall.args;
|
|
@@ -170,6 +180,16 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
170
180
|
? await evidence.trackWrite(path, async () => handler(request)) : await previewRetries.run(request, handler);
|
|
171
181
|
if (save && 'content' in result && (!('status' in result) || result.status !== 'error'))
|
|
172
182
|
await evidence.accept(save, result.content);
|
|
183
|
+
if ('content' in result && (!('status' in result) || result.status !== 'error')) {
|
|
184
|
+
const receipt = (0, dashboard_receipt_1.createdDashboard)(result.content);
|
|
185
|
+
if (receipt)
|
|
186
|
+
return new langgraph_1.Command({ update: { messages: [result], ...editing.select({ schemaVersion: 1, artifactId: receipt.artifactId, draftRevision: receipt.draftRevision }) } });
|
|
187
|
+
if (name === 'dashboard_open' && typeof result.content === 'string') {
|
|
188
|
+
const opened = v3_1.z.object({ artifactId: v3_1.z.string().uuid(), readVersionId: v3_1.z.string().uuid().optional(), expectedRevision: v3_1.z.number() }).safeParse(JSON.parse(result.content));
|
|
189
|
+
if (opened.success && !opened.data.readVersionId)
|
|
190
|
+
return new langgraph_1.Command({ update: { messages: [result], ...editing.select({ schemaVersion: 1, artifactId: opened.data.artifactId, ...(opened.data.expectedRevision > 0 ? { draftRevision: opened.data.expectedRevision } : {}) }) } });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
173
193
|
return result;
|
|
174
194
|
}, wrapModelCall: async (request, handler) => {
|
|
175
195
|
if (previewRetries.exhausted) {
|
|
@@ -181,12 +201,12 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
181
201
|
// A noncompliant model must not restart the failed loop even after tools were removed.
|
|
182
202
|
return result?.tool_calls?.length ? new messages_1.AIMessage(summary) : result;
|
|
183
203
|
}
|
|
184
|
-
const exhausted = ++modelCalls >
|
|
204
|
+
const exhausted = ++modelCalls > options.maxModelCalls;
|
|
185
205
|
if (exhausted && evidence.pending)
|
|
186
206
|
throw new Error('DASHBOARD_SAVE_NOT_CONFIRMED: no successful draft save receipt; Workspace changes have not been saved to the dashboard.');
|
|
187
207
|
const result = await handler({ ...request, ...(evidence.pending ? { toolChoice: 'required' } : {}), ...(exhausted ? { tools: [] } : {}), systemMessage: new messages_1.SystemMessage({ content: [
|
|
188
208
|
...(typeof request.systemMessage?.content === 'string' ? [{ type: 'text', text: request.systemMessage.content }] : request.systemMessage?.content ?? []),
|
|
189
|
-
{ type: 'text', text: exports.DASHBOARD_GUIDANCE + '\n' + definition_tools_1.DEFINITION_GUIDANCE + '\n' + html_guidance_1.HTML_DASHBOARD_GUIDANCE + '\n' + editing_1.EDITING_GUIDANCE + (evidence.pending ? `\nDashboard changes are pending without a matching draft save receipt. Unsaved files: ${JSON.stringify(evidence.pendingPaths)}. Continue reading/repairing and call dashboard_create_html or dashboard_update with the exact file path; do not finish or claim it was saved. When abandoning earlier unsaved HTML creation candidates, explicitly pass their exact paths as supersedesPaths to dashboard_create or dashboard_create_html, matching the requested presentation mode. If a standard dashboard is already saved, repeat dashboard_create with the same definition/previewIds and supersedesPaths; do not create an unwanted HTML dashboard. This only abandons those candidates after a successful save; it never discards another Artifact editing copy.` : '') + (options.allowedFinalProviders ? `\nThis Assistant requires every saved dashboard binding to use one of these providers: ${options.allowedFinalProviders.join(', ')}. Other providers may be previewed only as upstream inputs. Do not save a direct-source substitute.` : '') + (exhausted ? '\nThe dashboard tool budget is exhausted. Stop calls; report only saved receipts or explain the concrete blocker truthfully.' : '') }
|
|
209
|
+
{ type: 'text', text: exports.DASHBOARD_GUIDANCE + (editing.current() ? `\nCurrent editing target: ${JSON.stringify(editing.current())}. Continue this Artifact with dashboard_open/update unless the user explicitly requests a new independent dashboard.` : '') + '\n' + definition_tools_1.DEFINITION_GUIDANCE + '\n' + html_guidance_1.HTML_DASHBOARD_GUIDANCE + '\n' + editing_1.EDITING_GUIDANCE + (evidence.pending ? `\nDashboard changes are pending without a matching draft save receipt. Unsaved files: ${JSON.stringify(evidence.pendingPaths)}. Continue reading/repairing and call dashboard_create_html or dashboard_update with the exact file path; do not finish or claim it was saved. When abandoning earlier unsaved HTML creation candidates, explicitly pass their exact paths as supersedesPaths to dashboard_create or dashboard_create_html, matching the requested presentation mode. If a standard dashboard is already saved, repeat dashboard_create with the same definition/previewIds and supersedesPaths; do not create an unwanted HTML dashboard. This only abandons those candidates after a successful save; it never discards another Artifact editing copy.` : '') + (options.allowedFinalProviders ? `\nThis Assistant requires every saved dashboard binding to use one of these providers: ${options.allowedFinalProviders.join(', ')}. Other providers may be previewed only as upstream inputs. Do not save a direct-source substitute.` : '') + (exhausted ? '\nThe dashboard tool budget is exhausted. Stop calls; report only saved receipts or explain the concrete blocker truthfully.' : '') }
|
|
190
210
|
] }) });
|
|
191
211
|
if (evidence.pending && result && !result.tool_calls?.length)
|
|
192
212
|
throw new Error('DASHBOARD_SAVE_NOT_CONFIRMED: the model stopped without a successful draft save receipt.');
|
|
@@ -194,9 +214,9 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
194
214
|
}, tools: [
|
|
195
215
|
filterEvidence.tool,
|
|
196
216
|
...(0, definition_tools_1.createDefinitionTools)(context, () => { listedSources = undefined; }),
|
|
197
|
-
(0, tools_1.tool)(async () => JSON.stringify({ libraries: await (0, document_libraries_1.
|
|
198
|
-
online: { ...document_network_1.DASHBOARD_NETWORK_POLICY,
|
|
199
|
-
usage: '
|
|
217
|
+
(0, tools_1.tool)(async () => JSON.stringify({ libraries: (await (0, document_libraries_1.bundledLibraries)()).map(({ source, ...lock }) => lock),
|
|
218
|
+
online: { enabled: true, ...document_network_1.DASHBOARD_NETWORK_POLICY,
|
|
219
|
+
usage: 'Network access is temporarily unrestricted for functional acceptance: CDN scripts/styles/fonts, external images, CSS imports and fetch/XHR are available, subject to browser CORS and mixed-content rules. Tailwind CDN is supported. Use exact versions when possible. Business data from platform sources must still use window.xpertLiveArtifact and saved Bindings; never embed credentials.' },
|
|
200
220
|
pageRuntime: {
|
|
201
221
|
global: 'window.xpertLiveArtifact',
|
|
202
222
|
bindingIds: [...new Set([...previews.values()].map(binding => binding.id))],
|
|
@@ -204,11 +224,15 @@ let DashboardMiddleware = class DashboardMiddleware {
|
|
|
204
224
|
refresh: 'live.refresh(bindingId) requires a Binding ID. live.refresh() without an ID is invalid. For a page refresh button or timer, call Promise.all(bindingIds.map(id => live.refresh(id))). Each subscription redraws its KPI, chart and details.',
|
|
205
225
|
filters: 'Mark native data selects with data-dashboard-control="<exact controlId>". Mark purely visual selects with data-dashboard-presentation instead. Changing a data select must call live.query for every affected Binding, not only filter cached rows in JS. bindSelect updates one Binding only. Read references/html-lifecycle.md before writing the page.'
|
|
206
226
|
},
|
|
207
|
-
usage: {
|
|
227
|
+
usage: { 'trend-workspace': 'window.TrendWorkspace: pale-blue KPI rail and aligned trends. Read themes/trend-workspace/README.md.',
|
|
228
|
+
'profit-atlas': 'window.ProfitAtlas: dark profitability workbench, horizontal KPIs, scatter-first analysis and signed rankings. Read themes/profit-atlas/README.md.',
|
|
229
|
+
'customer-brief': 'window.CustomerBrief: warm editorial customer brief, serif hierarchy, grouped return metrics and segment comparisons. Read themes/customer-brief/README.md.',
|
|
230
|
+
themes: 'Select exactly one theme with echarts. Each provides enhanceSelect(nativeSelect) and charts.line/horizontal/scatter with isolated CSS and pinned bytes. Read themes/README.md; preserve an existing dashboard theme unless the user requests a change.',
|
|
231
|
+
echarts: 'window.echarts: init(element, null, {renderer:"svg"}) then setOption(completeOption, {notMerge:true}). Canvas is also available. Derive active series/legend dimensions from each received Dataset, including filtered results; never retain excluded groups as zero-valued series. Aggregate repeated categories using all grain dimensions, clear empty results, and redraw KPI, chart and details together in subscribe. Use ResizeObserver to resize and reuse the instance on filter/refresh.',
|
|
208
232
|
three: 'window.THREE: bundled core including WebGLRenderer. Requires WebGL2; catch unavailable GPU contexts and show a clear fallback. External textures/models, loaders/addons, WebGPU and workers are not bundled.' },
|
|
209
|
-
lifecycle: 'Pass packaged library IDs to dashboard_create_html or dashboard_update. Actual version and bytes are pinned on save; omitted libraries on update preserves saved locks. Online resources
|
|
233
|
+
lifecycle: 'Pass packaged library IDs to dashboard_create_html or dashboard_update. Actual version and bytes are pinned on save; omitted libraries on update preserves saved locks. Online resources must load successfully during preflight and viewing; they are not frozen with the Artifact.' }), { name: 'dashboard_libraries', description: 'Discover packaged libraries, themes, exact versions and the current unrestricted network policy. Tailwind CDN and other online dependencies are supported. Returns metadata, never library source.',
|
|
210
234
|
schema: v3_1.z.object({}).strict(), verboseParsingErrors: true, metadata: { toolName: { en_US: 'Discover dashboard libraries', zh_Hans: '查看看板前端图库' } } }),
|
|
211
|
-
...(0, editing_1.createEditingTools)(this.service, scope, context, resolvePreviews, validateFinal, (path, artifactId) => evidence.opened(path, artifactId)),
|
|
235
|
+
...(0, editing_1.createEditingTools)(this.service, scope, context, resolvePreviews, validateFinal, (path, artifactId) => evidence.opened(path, artifactId), editing.resolve),
|
|
212
236
|
(0, tools_1.tool)(async () => {
|
|
213
237
|
listedSources = await this.service.sources(scope);
|
|
214
238
|
return JSON.stringify(listedSources);
|