@xpert-ai/plugin-live-dashboard 0.2.0 → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xpert-ai/plugin-live-dashboard",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "level": "system",
5
5
  "artifactNamespace": "live_dashboard",
6
6
  "sandboxActions": "./dist/sandbox-actions/action.json",
package/README.md CHANGED
@@ -57,12 +57,77 @@ Preview/save also probe a declared non-default filter value and, when applicable
57
57
 
58
58
  Artifacts are owner-only within their agent/project host for this MVP. MIME: `application/json`; resource type: `live-dashboard`; namespace: `live_dashboard`. The Workbench supports selection, JSON import/edit, typed filters, refresh, version/freshness and partial-result notices.
59
59
 
60
+ ## Built-in prompt workflows / 内置提示词模板
61
+
62
+ When the Assistant has the `LiveDashboard` middleware, type `/dashboard-` in its
63
+ chat composer and select a workflow. Selection inserts an invocation so the user
64
+ can add requirements before sending; it does not submit or publish automatically.
65
+ Commands are contributed by the installed middleware, so existing Assistants can
66
+ use them after the updated plugin is loaded. No Assistant-template import or
67
+ database seeding is needed. The host must support middleware slash commands.
68
+
69
+ | Mode / 分类 | Command | 用途 |
70
+ | --- | --- | --- |
71
+ | Standard | `/dashboard-standard-auto` | 根据真实数据质量和业务价值自动选题,新建独立标准看板 |
72
+ | Standard | `/dashboard-standard-new` | 围绕指定主题新建标准看板 |
73
+ | Standard | `/dashboard-standard-improve` | 调整指定看板的图表、指标、筛选,保留 Artifact 身份 |
74
+ | Standard | `/dashboard-standard-recover` | 定位失败步骤,用本轮证据恢复标准草稿保存 |
75
+ | HTML | `/dashboard-html-auto` | 自动选题,新建布局精致、可实际使用的 HTML 看板 |
76
+ | HTML | `/dashboard-html-new` | 围绕指定业务问题、受众和视觉要求新建 HTML 看板 |
77
+ | HTML | `/dashboard-html-style` | 参考图片或风格描述美化已有 HTML 看板,保留查询与交互 |
78
+ | HTML | `/dashboard-html-recover` | 保留页面候选,按真实校验错误修复并恢复保存 |
79
+ | Inspect | `/dashboard-explore` | 只读探索数据源、字段、日期覆盖和候选业务主题 |
80
+ | Inspect | `/dashboard-test-source` | 最小真实查询、字段映射和筛选验证 |
81
+ | Inspect | `/dashboard-audit-metrics` | 只读核对计算、单位、期间和关联粒度 |
82
+ | Inspect | `/dashboard-verify` | 核对保存版本、筛选、刷新,并标明未执行的页面验收 |
83
+
84
+ Examples (replace the descriptive inputs with your own requirements):
85
+
86
+ ```text
87
+ /dashboard-standard-auto 使用当前组织的 BI 数据源,为采购主管挑选一个数据完整、能帮助识别交付问题的主题。新建独立看板。
88
+ /dashboard-standard-new 使用库存数据,面向仓库主管创建库存积压看板。核实库龄和库存金额口径,提供仓库与日期筛选。
89
+ /dashboard-html-auto 从已授权数据中选择一个能支持日常运营决策的主题。面向部门负责人,浅色企业风格,摘要指标、主趋势、关注清单和明细。
90
+ /dashboard-html-new 创建供应商交付分析看板。使用已授权采购数据,核实交付及时率口径;参考附图的留白、层次和配色,不复制示例数字。
91
+ /dashboard-html-style 美化当前选中的 HTML 看板,参考附图布局;保留现有指标、绑定、筛选和刷新,只调整视觉。
92
+ /dashboard-html-recover 继续保存刚才失败的 HTML 候选。读取实际文件与错误,重新获取本轮所需预览;如果运行时仍不可用,报告准确阻塞。
93
+ /dashboard-test-source 检查当前采购数据源的一个有实际数据的查询,验证一个供应商筛选及全部供应商。
94
+ /dashboard-verify 检查当前看板的默认日期、一个真实筛选值和全部值;区分查询验证与待人工页面验证。
95
+ ```
96
+
97
+ Provide a source name, business question, audience and date range where relevant;
98
+ HTML requests can include a reference image or style. IDs, provider contracts and
99
+ paths are discovered from tools, never hard-coded into the templates. Automatic
100
+ selection ranks business usefulness and data readiness; specified-topic workflows
101
+ do not silently substitute another topic. New HTML workflows choose an unused
102
+ file path and never overwrite the selected dashboard.
103
+
104
+ The templates guide real queries, metric checks, run-local previews/filter tests
105
+ and successful draft-save receipts. They do not grant source access or install a
106
+ missing Browser Runtime. HTML saves still require runtime validation. Native
107
+ dashboards keep their own renderer and supported chart/table schema. Formal
108
+ publication remains a human action. Inspection commands do not register
109
+ definitions, edit business data or save dashboards; a tool-level pass is not a
110
+ claim of visual acceptance.
111
+
112
+ ### Manual acceptance after loading the plugin
113
+
114
+ 1. In an Assistant with LiveDashboard, open the `/` picker and search `dashboard`.
115
+ Verify all twelve localized entries; selecting one should leave an editable
116
+ invocation in the composer.
117
+ 2. Run one standard-new and one HTML-new request against an authorized test source.
118
+ Verify independent Artifact IDs, fresh previews and successful draft receipts;
119
+ HTML also requires its normal Browser Runtime check.
120
+ 3. Reopen each saved draft, change a real filter and refresh. Confirm real data
121
+ updates. Run an inspection command and verify it does not save a new revision.
122
+
60
123
  ## HTML mode
61
124
 
62
125
  See [HTML mode and acceptance](docs/html-mode.md). Agent tools write a complete single-file document to the authorized file workspace, then read and copy its bytes into the immutable dashboard JSON version alongside Bindings and Controls. Before creating an Artifact, a plugin-owned Sandbox Action runs the page with real preview datasets in the platform Browser Runtime, through the sandbox-browser queue. Unavailable runtime or failed initial rendering blocks HTML save and returns diagnostics to the Agent. No live workspace path is dereferenced on reopening. A changed file requires a new saved version. Existing JSON-only dashboards remain compatible.
63
126
 
64
127
  The platform browser entry `@xpert-ai/plugin-sdk/artifact-document` owns the sandbox, CSP, MessageChannel, request validation and latest-response policy. The plugin owns lifecycle and supplies a narrow callback to `query-binding`. Its server loads the exact saved Artifact version, finds the declared Binding, validates controls and rechecks source access. The endpoint rejects full Binding, Provider, SQL/payload and alternate source fields.
65
128
 
129
+ HTML preflight checks each native select's alternative/restored values and each button path in a fresh document mount, with at most two pages active. A button path also clicks controls it inserts, reveals or enables, retaining their prerequisite state and the same query quota; traversal is bounded to the first 12 buttons and 12 clicks per path. Every scenario checks initial bindings and host refresh using the same preview datasets. Successful static resources can be reused within this validation (bounded to 32 MB, up to 8 MB per resource); every replay still passes the resource policy, and failed, redirected or non-cacheable responses are not replayed. A 55-second validation deadline fails closed and cancels remaining pages before the host's 60-second Action limit. This prevents repeated resource downloads and the synthetic interaction sweep from exhausting the Action budget or one document's rate window without raising the SDK's query/concurrency limits. A request storm within a scenario still blocks saving; preflight is not a full combinatorial or sustained-load test.
130
+
66
131
  Pages call `window.xpertLiveArtifact.ready()`, `subscribe(bindingId, render)`, `query(bindingId, controls)` and `refresh(bindingId)`. Register subscriptions before the first query so the toolbar can refresh without resetting the document. Use inline DOM/SVG/Canvas or online scripts/styles/fonts from the HTTPS origins returned by `dashboard_libraries.online`. Tailwind CDN, jsDelivr, cdnjs, unpkg and Google Fonts are supported according to their resource-type allowlist. Preflight and the displayed page use the same policy; failed loads prevent saving. Pin online versions where possible. Unlike packaged libraries, online bytes are not part of the immutable Artifact snapshot. Direct data requests, external images, eval, workers and frames remain unavailable. Script processing remains in the separate Workspace Script provider.
67
132
 
68
133
  HTML is capped at 300 KB; the whole saved definition remains capped at 600 KB. HTML pages own their chart layout, so their charts/tables arrays are empty. The standard renderer remains an independent option. Sharing, data permissions and source limits are unchanged.
@@ -107,3 +172,11 @@ The Share action publishes a link to an already published dashboard: follow the
107
172
  See [team sharing and standalone pages](docs/team-sharing.mdx) and [local acceptance](docs/team-sharing-acceptance.mdx). This feature needs a host exposing the Artifact Presentation registry, API and page; it cannot be installed on an older SDK alone.
108
173
 
109
174
  Chat messages use the platform resource-card protocol after a successful create, update or open. The card opens the exact dashboard in Workbench; no dashboard renderer or queries are embedded in messages. See [chat resource cards](docs/chat-resource-cards.mdx).
175
+
176
+ ### Delete a saved dashboard
177
+
178
+ Open the dashboard picker and use the trash icon beside an entry. The confirmation shows its title and Artifact ID, so same-name dashboards can be distinguished. Deletion recycles the whole dashboard (draft and published versions), removes it from the active list and revokes shared links; it does not delete source data or Assistant workspace files. Deleting the selected dashboard clears its preview and Assistant context; deleting another dashboard preserves the current view.
179
+
180
+ The owner can delete private Assistant dashboards; Project dashboards require the current user's management permission. Read-only shared pages expose no delete control. The platform checks the confirmed draft revision atomically, rejecting concurrent edits. Entries without a saved working draft (legacy version-only or incomplete first saves) have no recycle revision and do not expose this action. No Agent deletion tool is registered.
181
+
182
+ Manual acceptance after installing the updated plugin: cancel a deletion and confirm the entry remains; delete an unused saved dashboard and confirm it stays absent after reload; delete the selected dashboard and confirm the preview clears and its old shared link is unavailable.
@@ -6,6 +6,7 @@ export declare const dashboardSummarySchema: z.ZodObject<{
6
6
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
7
7
  updatedAt: z.ZodOptional<z.ZodString>;
8
8
  draftRevision: z.ZodOptional<z.ZodNumber>;
9
+ canDelete: z.ZodOptional<z.ZodBoolean>;
9
10
  isDraft: z.ZodOptional<z.ZodBoolean>;
10
11
  baseVersionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
11
12
  }, "strip", z.ZodTypeAny, {
@@ -17,6 +18,7 @@ export declare const dashboardSummarySchema: z.ZodObject<{
17
18
  baseVersionId?: string | null | undefined;
18
19
  isDraft?: boolean | undefined;
19
20
  updatedAt?: string | undefined;
21
+ canDelete?: boolean | undefined;
20
22
  }, {
21
23
  artifactId: string;
22
24
  title?: string | null | undefined;
@@ -26,6 +28,7 @@ export declare const dashboardSummarySchema: z.ZodObject<{
26
28
  baseVersionId?: string | null | undefined;
27
29
  isDraft?: boolean | undefined;
28
30
  updatedAt?: string | undefined;
31
+ canDelete?: boolean | undefined;
29
32
  }>;
30
33
  export declare const dashboardSavedSchema: z.ZodObject<{
31
34
  artifactId: z.ZodString;
@@ -34,6 +37,7 @@ export declare const dashboardSavedSchema: z.ZodObject<{
34
37
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
38
  updatedAt: z.ZodOptional<z.ZodString>;
36
39
  draftRevision: z.ZodOptional<z.ZodNumber>;
40
+ canDelete: z.ZodOptional<z.ZodBoolean>;
37
41
  isDraft: z.ZodOptional<z.ZodBoolean>;
38
42
  baseVersionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
39
43
  } & {
@@ -365,6 +369,7 @@ export declare const dashboardSavedSchema: z.ZodObject<{
365
369
  baseVersionId?: string | null | undefined;
366
370
  isDraft?: boolean | undefined;
367
371
  updatedAt?: string | undefined;
372
+ canDelete?: boolean | undefined;
368
373
  }, {
369
374
  manifest: {
370
375
  schema: "xpert.live-dashboard";
@@ -421,6 +426,7 @@ export declare const dashboardSavedSchema: z.ZodObject<{
421
426
  baseVersionId?: string | null | undefined;
422
427
  isDraft?: boolean | undefined;
423
428
  updatedAt?: string | undefined;
429
+ canDelete?: boolean | undefined;
424
430
  }>;
425
431
  export declare const dashboardViewDataSchema: z.ZodObject<{
426
432
  meta: z.ZodObject<{
@@ -453,6 +459,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
453
459
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
454
460
  updatedAt: z.ZodOptional<z.ZodString>;
455
461
  draftRevision: z.ZodOptional<z.ZodNumber>;
462
+ canDelete: z.ZodOptional<z.ZodBoolean>;
456
463
  isDraft: z.ZodOptional<z.ZodBoolean>;
457
464
  baseVersionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
458
465
  }, "strip", z.ZodTypeAny, {
@@ -464,6 +471,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
464
471
  baseVersionId?: string | null | undefined;
465
472
  isDraft?: boolean | undefined;
466
473
  updatedAt?: string | undefined;
474
+ canDelete?: boolean | undefined;
467
475
  }, {
468
476
  artifactId: string;
469
477
  title?: string | null | undefined;
@@ -473,6 +481,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
473
481
  baseVersionId?: string | null | undefined;
474
482
  isDraft?: boolean | undefined;
475
483
  updatedAt?: string | undefined;
484
+ canDelete?: boolean | undefined;
476
485
  }>, "many">;
477
486
  sources: z.ZodArray<z.ZodObject<{
478
487
  source: z.ZodType<import("@xpert-ai/contracts").AnalyticsSourceRef, z.ZodTypeDef, import("@xpert-ai/contracts").AnalyticsSourceRef>;
@@ -491,6 +500,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
491
500
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
492
501
  updatedAt: z.ZodOptional<z.ZodString>;
493
502
  draftRevision: z.ZodOptional<z.ZodNumber>;
503
+ canDelete: z.ZodOptional<z.ZodBoolean>;
494
504
  isDraft: z.ZodOptional<z.ZodBoolean>;
495
505
  baseVersionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
496
506
  } & {
@@ -822,6 +832,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
822
832
  baseVersionId?: string | null | undefined;
823
833
  isDraft?: boolean | undefined;
824
834
  updatedAt?: string | undefined;
835
+ canDelete?: boolean | undefined;
825
836
  }, {
826
837
  manifest: {
827
838
  schema: "xpert.live-dashboard";
@@ -878,6 +889,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
878
889
  baseVersionId?: string | null | undefined;
879
890
  isDraft?: boolean | undefined;
880
891
  updatedAt?: string | undefined;
892
+ canDelete?: boolean | undefined;
881
893
  }>>;
882
894
  versions: z.ZodOptional<z.ZodArray<z.ZodObject<{
883
895
  artifactId: z.ZodString;
@@ -886,6 +898,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
886
898
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
887
899
  updatedAt: z.ZodOptional<z.ZodString>;
888
900
  draftRevision: z.ZodOptional<z.ZodNumber>;
901
+ canDelete: z.ZodOptional<z.ZodBoolean>;
889
902
  isDraft: z.ZodOptional<z.ZodBoolean>;
890
903
  baseVersionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
891
904
  }, "strip", z.ZodTypeAny, {
@@ -897,6 +910,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
897
910
  baseVersionId?: string | null | undefined;
898
911
  isDraft?: boolean | undefined;
899
912
  updatedAt?: string | undefined;
913
+ canDelete?: boolean | undefined;
900
914
  }, {
901
915
  artifactId: string;
902
916
  title?: string | null | undefined;
@@ -906,6 +920,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
906
920
  baseVersionId?: string | null | undefined;
907
921
  isDraft?: boolean | undefined;
908
922
  updatedAt?: string | undefined;
923
+ canDelete?: boolean | undefined;
909
924
  }>, "many">>;
910
925
  }, "strip", z.ZodTypeAny, {
911
926
  sources: {
@@ -921,6 +936,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
921
936
  baseVersionId?: string | null | undefined;
922
937
  isDraft?: boolean | undefined;
923
938
  updatedAt?: string | undefined;
939
+ canDelete?: boolean | undefined;
924
940
  }[];
925
941
  saved?: {
926
942
  manifest: {
@@ -965,6 +981,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
965
981
  baseVersionId?: string | null | undefined;
966
982
  isDraft?: boolean | undefined;
967
983
  updatedAt?: string | undefined;
984
+ canDelete?: boolean | undefined;
968
985
  } | undefined;
969
986
  navigationTarget?: {
970
987
  target: "workbench.view";
@@ -983,6 +1000,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
983
1000
  baseVersionId?: string | null | undefined;
984
1001
  isDraft?: boolean | undefined;
985
1002
  updatedAt?: string | undefined;
1003
+ canDelete?: boolean | undefined;
986
1004
  }[] | undefined;
987
1005
  }, {
988
1006
  sources: {
@@ -998,6 +1016,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
998
1016
  baseVersionId?: string | null | undefined;
999
1017
  isDraft?: boolean | undefined;
1000
1018
  updatedAt?: string | undefined;
1019
+ canDelete?: boolean | undefined;
1001
1020
  }[];
1002
1021
  saved?: {
1003
1022
  manifest: {
@@ -1055,6 +1074,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1055
1074
  baseVersionId?: string | null | undefined;
1056
1075
  isDraft?: boolean | undefined;
1057
1076
  updatedAt?: string | undefined;
1077
+ canDelete?: boolean | undefined;
1058
1078
  } | undefined;
1059
1079
  navigationTarget?: {
1060
1080
  target: "workbench.view";
@@ -1073,6 +1093,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1073
1093
  baseVersionId?: string | null | undefined;
1074
1094
  isDraft?: boolean | undefined;
1075
1095
  updatedAt?: string | undefined;
1096
+ canDelete?: boolean | undefined;
1076
1097
  }[] | undefined;
1077
1098
  }>;
1078
1099
  }, "strip", z.ZodTypeAny, {
@@ -1090,6 +1111,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1090
1111
  baseVersionId?: string | null | undefined;
1091
1112
  isDraft?: boolean | undefined;
1092
1113
  updatedAt?: string | undefined;
1114
+ canDelete?: boolean | undefined;
1093
1115
  }[];
1094
1116
  saved?: {
1095
1117
  manifest: {
@@ -1134,6 +1156,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1134
1156
  baseVersionId?: string | null | undefined;
1135
1157
  isDraft?: boolean | undefined;
1136
1158
  updatedAt?: string | undefined;
1159
+ canDelete?: boolean | undefined;
1137
1160
  } | undefined;
1138
1161
  navigationTarget?: {
1139
1162
  target: "workbench.view";
@@ -1152,6 +1175,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1152
1175
  baseVersionId?: string | null | undefined;
1153
1176
  isDraft?: boolean | undefined;
1154
1177
  updatedAt?: string | undefined;
1178
+ canDelete?: boolean | undefined;
1155
1179
  }[] | undefined;
1156
1180
  };
1157
1181
  }, {
@@ -1169,6 +1193,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1169
1193
  baseVersionId?: string | null | undefined;
1170
1194
  isDraft?: boolean | undefined;
1171
1195
  updatedAt?: string | undefined;
1196
+ canDelete?: boolean | undefined;
1172
1197
  }[];
1173
1198
  saved?: {
1174
1199
  manifest: {
@@ -1226,6 +1251,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1226
1251
  baseVersionId?: string | null | undefined;
1227
1252
  isDraft?: boolean | undefined;
1228
1253
  updatedAt?: string | undefined;
1254
+ canDelete?: boolean | undefined;
1229
1255
  } | undefined;
1230
1256
  navigationTarget?: {
1231
1257
  target: "workbench.view";
@@ -1244,6 +1270,7 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
1244
1270
  baseVersionId?: string | null | undefined;
1245
1271
  isDraft?: boolean | undefined;
1246
1272
  updatedAt?: string | undefined;
1273
+ canDelete?: boolean | undefined;
1247
1274
  }[] | undefined;
1248
1275
  };
1249
1276
  }>;
@@ -6,7 +6,7 @@ const analytics_1 = require("@xpert-ai/plugin-sdk/analytics");
6
6
  const artifact_document_1 = require("@xpert-ai/plugin-sdk/artifact-document");
7
7
  const dashboard_schema_1 = require("./dashboard.schema");
8
8
  const dashboard_navigation_1 = require("./dashboard-navigation");
9
- exports.dashboardSummarySchema = v3_1.z.object({ artifactId: v3_1.z.string(), versionId: v3_1.z.string().nullish(), versionNumber: v3_1.z.number().optional(), title: v3_1.z.string().nullish(), updatedAt: v3_1.z.string().optional(), draftRevision: v3_1.z.number().optional(), isDraft: v3_1.z.boolean().optional(), baseVersionId: v3_1.z.string().nullish() });
9
+ exports.dashboardSummarySchema = v3_1.z.object({ artifactId: v3_1.z.string(), versionId: v3_1.z.string().nullish(), versionNumber: v3_1.z.number().optional(), title: v3_1.z.string().nullish(), updatedAt: v3_1.z.string().optional(), draftRevision: v3_1.z.number().optional(), canDelete: v3_1.z.boolean().optional(), isDraft: v3_1.z.boolean().optional(), baseVersionId: v3_1.z.string().nullish() });
10
10
  exports.dashboardSavedSchema = exports.dashboardSummarySchema.extend({ manifest: dashboard_schema_1.dashboardSchema, dependencies: artifact_document_1.artifactDocumentDependencyAssets.optional() });
11
11
  // Source identities belong to Analytics, including immutable Definitions and Artifacts.
12
12
  // The viewer consumes only the reference and label; DataSource fields are not universal.
@@ -12,11 +12,16 @@ export declare class DashboardService {
12
12
  preview(context: XpertResolvedViewHostContext, input: AnalyticsQueryRequest): Promise<import("@xpert-ai/contracts").AnalyticalDataset>;
13
13
  list(context: XpertResolvedViewHostContext): Promise<{
14
14
  title: string | null | undefined;
15
+ draftRevision?: number | undefined;
16
+ canDelete: boolean;
15
17
  artifactId: string;
16
18
  versionId: string | null | undefined;
17
19
  versionNumber: number | undefined;
18
20
  updatedAt: string | Date | undefined;
19
21
  }[]>;
22
+ trash(context: XpertResolvedViewHostContext, artifactId: string, expectedRevision: number): Promise<{
23
+ artifactId: string;
24
+ }>;
20
25
  save(context: XpertResolvedViewHostContext, manifest: DashboardManifest, expectedVersionId: string | null, expectedRevision?: number): Promise<{
21
26
  artifactId: string;
22
27
  draftId: string;
@@ -244,7 +249,7 @@ export declare class DashboardService {
244
249
  }>;
245
250
  queryBinding(context: XpertResolvedViewHostContext, artifactId: string, versionId: string | undefined, bindingId: string, input: Record<string, AnalyticsValue>, draftRevision?: number): Promise<import("@xpert-ai/contracts").AnalyticalDataset>;
246
251
  /** Every operation uses the current human's Project role; data queries still use actor(context). */
247
- authorizeProject(context: XpertResolvedViewHostContext, operation?: 'read' | 'write' | 'manage'): Promise<void>;
252
+ authorizeProject(context: XpertResolvedViewHostContext, operation?: 'read' | 'write' | 'manage'): Promise<import("@xpert-ai/plugin-sdk").ProjectHumanAccess | undefined>;
248
253
  private execute;
249
254
  private probeControls;
250
255
  }
@@ -40,11 +40,25 @@ let DashboardService = class DashboardService {
40
40
  return dataset;
41
41
  }
42
42
  async list(context) {
43
- await this.authorizeProject(context);
43
+ const access = await this.authorizeProject(context);
44
44
  const result = await this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability).listArtifacts({ pluginName: exports.PLUGIN_NAME, resourceType: RESOURCE_TYPE, resourceIdPrefix: hostPrefix(context), status: 'active', pageSize: 100, includeCurrentVersion: true });
45
45
  const items = result.items.filter((item) => item.resourceId.startsWith(hostPrefix(context)) && (item.userId === context.userId || !item.userId && item.projectId === projectId(context)));
46
46
  const drafts = new Map((await this.runtime.require(plugin_sdk_1.ArtifactDraftsRuntimeCapability).list(items.map(item => item.id))).map(draft => [draft.artifactId, draft]));
47
- return items.map(item => ({ ...summary(item), ...(drafts.has(item.id) ? { title: drafts.get(item.id).title ?? item.title } : {}) }));
47
+ return items.map(item => {
48
+ const draft = drafts.get(item.id);
49
+ return { ...summary(item), canDelete: !!draft && (!projectId(context) || access?.canManage === true),
50
+ ...(draft ? { title: draft.title ?? item.title, draftRevision: draft.revision } : {}) };
51
+ });
52
+ }
53
+ async trash(context, artifactId, expectedRevision) {
54
+ await this.authorizeProject(context, 'manage');
55
+ const artifact = await this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability).getArtifact(artifactId);
56
+ assertOwned(context, artifact);
57
+ if (artifact.status !== 'active')
58
+ throw new common_1.ForbiddenException('DASHBOARD_ARCHIVED');
59
+ // Reuse the platform's atomic revision check, recycle state and share revocation.
60
+ await this.runtime.require(plugin_sdk_1.ArtifactDraftsRuntimeCapability).setRecycled({ artifactId, expectedRevision, recycled: true });
61
+ return { artifactId };
48
62
  }
49
63
  async save(context, manifest, expectedVersionId, expectedRevision = 0) {
50
64
  await this.authorizeProject(context, 'write');
@@ -175,11 +189,13 @@ let DashboardService = class DashboardService {
175
189
  if (context.hostType === 'agent')
176
190
  await access.assertAssistant({ ...input, assistantId: context.hostId });
177
191
  if (operation === 'write')
178
- await access.assertEdit(input);
179
- else if (operation === 'manage')
180
- await access.assertManage(input);
181
- else if (!(await access.listReadable({ actor: scopedActor, projectIds: [project] })).length)
192
+ return access.assertEdit(input);
193
+ if (operation === 'manage')
194
+ return access.assertManage(input);
195
+ const readable = (await access.listReadable({ actor: scopedActor, projectIds: [project] })).find(item => item.projectId === project);
196
+ if (!readable)
182
197
  throw new common_1.ForbiddenException('DASHBOARD_ACCESS_DENIED');
198
+ return readable;
183
199
  }
184
200
  execute(context, manifest, input) {
185
201
  return (0, dashboard_queries_1.queryDashboard)(this.runtime, actor(context), manifest, input);
@@ -33,6 +33,7 @@ const save_evidence_1 = require("./save-evidence");
33
33
  const resource_card_1 = require("./resource-card");
34
34
  const dashboard_icon_1 = require("./dashboard-icon");
35
35
  const preview_retry_1 = require("./preview-retry");
36
+ const prompt_workflows_1 = require("./prompt-workflows");
36
37
  const middlewareOptionsSchema = v3_1.z.object({ allowedFinalProviders: v3_1.z.array(v3_1.z.string().min(1)).min(1).max(20).optional() }).strict().default({});
37
38
  exports.DASHBOARD_GUIDANCE = `For a new independent dashboard, use a new unused HTML file path. An existing filename or matching title is not authorization to edit another Artifact; do not switch from creation to dashboard_open/update because a file already exists. For a new dashboard, call dashboard_list_sources before searching raw files, reading old scripts or creating transformations. Named governed sources may already provide the required query; inspect their provider contracts first. File-backed sources do not imply that a script must be written. For creating or editing live dashboards, first read the installed live-dashboard skill using read_skill_file and follow only the references relevant to the task. Use SandboxFile tools for all source-file authoring; HTML alone is not a saved dashboard. Follow preview.validation.checks immediately before authoring HTML; each suggestedCall must actually succeed. Business definitions, real data previews and nullable-filter tests are required before saving new or changed Bindings. Do not invent business data or substitute a different metric without agreement. Report completion only from a successful dashboard_create/dashboard_create_html/dashboard_update draft receipt. Human publication is separate. Successful create, update and open tools emit a chat resource card automatically; resourceCard.status reports emission. Its Open button selects the exact dashboard in Workbench. Never fabricate a link, call present_files for dashboard HTML, or output card JSON as text. If card delivery is unavailable, report the saved receipt and use the Workbench picker.`;
38
39
  let DashboardMiddleware = class DashboardMiddleware {
@@ -41,6 +42,7 @@ let DashboardMiddleware = class DashboardMiddleware {
41
42
  this.meta = {
42
43
  name: 'LiveDashboard', label: { en_US: 'Live dashboards', zh_Hans: '实时看板' },
43
44
  description: { en_US: 'Discover, preview, create and update governed live dashboards.', zh_Hans: '发现业务数据、验证查询并持续修改实时看板。' },
45
+ slashCommands: prompt_workflows_1.dashboardPromptWorkflows,
44
46
  // Tools inherit this self-contained icon through the platform middleware metadata.
45
47
  icon: dashboard_icon_1.dashboardIcon, features: [view_provider_1.FEATURE], configSchema: { type: 'object', properties: {
46
48
  allowedFinalProviders: { type: 'array', items: { type: 'string' }, title: { en_US: 'Allowed final dashboard providers', zh_Hans: '最终看板允许的 Provider' },
@@ -0,0 +1,3 @@
1
+ import type { SkillSlashCommand } from '@xpert-ai/contracts';
2
+ /** Commands are resolved from the installed middleware, including on existing Assistants. */
3
+ export declare const dashboardPromptWorkflows: SkillSlashCommand[];
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardPromptWorkflows = void 0;
4
+ const dashboard_icon_1 = require("./dashboard-icon");
5
+ const context = `Work in the current authorized Assistant/project scope. Use the user's language for the page and response. Read the installed live-dashboard skill through read_skill_file and follow the references relevant to this task. Respect provider policy, access controls and tool schemas. Never change deployment, credentials, Assistant configuration or business-source data.
6
+ Resolve source/provider pairs, Artifact IDs, fields and file paths from current tools, not names or previous conversation claims. Use only real query results; no invented business data, targets, thresholds, comparison periods or activity feeds. Keep queries read-only and bounded. Report actual tool failures and diagnosticId when supplied. A missing capability or runtime binding is a blocker, not permission to bypass validation or switch presentation modes.`;
7
+ const metrics = `Confirm metric definitions, units, time range, grain and join keys from metadata and small real samples. Compute ratios from aggregated numerators and denominators, not sums/averages of percentages. Keep unknown/zero denominators as unavailable, not zero. Check join cardinality and avoid duplicate totals. Use chronological date ordering and comparable complete periods. State freshness and gaps; historical data must not be described as current operations. Avoid exposing unnecessary personal or sensitive row-level fields.`;
8
+ const discover = `Call dashboard_list_sources first, then dashboard_discover for exact authorized source/provider pairs. Follow returned inspectRequest/nextRequest and query contracts; do not scan unrelated schemas or guess SQL fields. Prefer existing governed definitions. If the requested source is missing, use analytics_definition_connections and analytics_definition_inspect; register a missing definition with analytics_definition_register only when needed for this requested dashboard, then refresh sources. Never duplicate an existing definition or ask the user to supply internal IDs.`;
9
+ const preview = `Before saving new or changed Bindings, call dashboard_preview or dashboard_preview_binding with the exact final queries and typed default controls in this run. Execute every preview.validation.checks[].suggestedCall with dashboard_test_filter; use observed non-default values and the all-values/null case when applicable. Follow each tool's schema, serialize JSON-string fields correctly, and copy returned bindingJson rather than nesting a Binding inside SQL. Changed queries/defaults need fresh evidence. Use at most eight final Bindings, sharing a query where its metric, grain and filters permit it. Never reuse historical previewIds or hard-code preview rows into the page.`;
10
+ const receipt = `Save a working draft and require a successful domain receipt with dashboard.artifactId, status "draft" and draftRevision. File writes, an existing resource card or an older published version are not proof of this save. Open the exact saved Artifact to inspect it; do not update an unchanged copy just to verify persistence. Verify real filter changes and refresh where available, distinguishing tool checks from unperformed viewer checks. Return the saved receipt, sources, metric definitions and a short manual acceptance checklist. Formal publication remains a separate human Workbench action.`;
11
+ const newDashboard = `Create a NEW independent dashboard. Do not modify, rename or replace an existing Artifact, including the currently selected dashboard. Choose a distinct business title. In HTML mode choose an unused workspace-relative named .html path; never reuse an old page just because it has a similar title. Reuse verified source definitions, not an old dashboard's identity. If this run already saved the requested dashboard, keep its Artifact rather than creating a duplicate.`;
12
+ const automaticTheme = `Choose one useful business theme from the authorized data, prioritizing an operational decision such as delivery delays, inventory backlog, supplier performance or production quality. Compare only a few plausible sources by completeness, freshness, metric clarity and actionable detail; then select the strongest one without repeatedly asking the user to choose. Explain who will use it, which decision it supports and which records require attention. If no source supports a defensible theme, report the missing data instead of making a decorative demo.`;
13
+ const specifiedTheme = `Use the business theme, audience and question supplied by the user. Translate them into a small coherent set of metrics, trends, comparisons and actionable detail. If the theme is missing or a material business definition is ambiguous, ask one focused question. Do not silently replace the requested theme or data source. Omit unsupported metrics and explain the gap.`;
14
+ const standard = `Use the STANDARD dashboard definition and native charts/tables/controls with dashboard_create for a new dashboard. Do not author HTML, load ECharts, call dashboard_create_html or convert the dashboard to HTML. Choose only components supported by the current tool schema; express summary metrics with supported charts/tables rather than inventing a KPI-card type. Include a useful time trend, a business-dimension comparison, a bounded detail table (normally at most 50 rows), and supported filters. Bind all views to real queries so filter changes and refresh requery the source.`;
15
+ const html = `Use a custom HTML dashboard. Call dashboard_libraries and read the installed skill's HTML runtime/lifecycle reference before authoring. Check the actual available libraries and pageRuntime contract; do not assume Browser Runtime is healthy. Author through SandboxFile tools and save a new page with dashboard_create_html. The page must declare const live = window.xpertLiveArtifact, subscribe before await live.ready(), and call live.query(bindingId, typedControls) for initial load and all affected bindings on filter application. Refresh each exact Binding ID with live.refresh(bindingId). Data comes only through these declared bindings, never direct database/REST requests or embedded preview rows. Follow allowed library origins, locks and runtime validation; do not add arbitrary dependencies.`;
16
+ const design = `Build a polished business workspace, not a wall of large charts. Use a restrained light enterprise theme unless the user supplies another style: quiet page background, clean panels, consistent spacing, readable typography and one main accent. At desktop widths, place three or four meaningful summary metrics above a main trend/comparison area with a narrower attention list; place actionable detail below. Adapt to the actual embedded viewport and stack on narrow widths without clipping. Use compact chart heights, clear units, restrained gridlines, legible tooltips and deliberate whitespace. Attention lists and comparison badges require real evidence; otherwise omit them. Support loading, no-data, error and partial-data states distinctly. Display the effective filters, data period and last successful refresh, never a fabricated refresh timestamp. Keep interactions functional and keyboard accessible.`;
17
+ const existing = `Use only the explicitly selected dashboard or a uniquely identified target from dashboard_list. Ask for a target if ambiguous; never choose by recency. Call dashboard_open, inspect its presentation.type and read the current definition/editing copy. Preserve Artifact identity, saved Bindings, business semantics and library locks unless the requested change requires changing them. Copy saveArguments and revision fields from the current open result, include the requested/current title, and save real changes with dashboard_update. On revision conflict retain the edits and reconcile with the latest draft; do not overwrite blindly.`;
18
+ const recovery = `Inspect the actual failed call, its full returned error and the current saved/unsaved state first. A previous response quoting an error is not a fresh execution. If an earlier save outcome is unknown, inspect matching saved Artifacts before attempting creation again. Repair only the evidenced argument, query, filter or page defect. Obtain fresh previews and filter evidence in this run for new/changed Bindings, then retry the appropriate domain save. Do not repeatedly guess. For RUNTIME_UNBOUND, missing tools, permission failures or unavailable Browser Runtime, stop with the precise blocker and preserved file/Artifact references; do not edit infrastructure or downgrade presentation. Report success only from a new successful save receipt.`;
19
+ function command(prompt) {
20
+ return {
21
+ name: prompt.name,
22
+ label: prompt.label,
23
+ description: prompt.description,
24
+ icon: dashboard_icon_1.dashboardIcon,
25
+ category: 'live-dashboard',
26
+ kind: 'prompt_workflow',
27
+ workflow: { type: 'prompt_workflow', name: prompt.name, label: prompt.label, description: prompt.description, tags: ['live-dashboard', prompt.group] },
28
+ argsHint: prompt.argsHint,
29
+ action: { type: 'insert_invocation', template: [context, ...prompt.instructions, 'User requirements / 用户需求:', '{{args}}'].join('\n\n') }
30
+ };
31
+ }
32
+ /** Commands are resolved from the installed middleware, including on existing Assistants. */
33
+ exports.dashboardPromptWorkflows = [
34
+ {
35
+ name: 'dashboard-standard-auto', group: 'standard',
36
+ label: { en_US: 'Standard · Choose a business theme', zh_Hans: '标准看板 · 自动选题新建' },
37
+ description: { en_US: 'Choose a useful theme from real data and create an independent native dashboard.', zh_Hans: '根据数据质量和业务价值选题,新建可筛选、刷新的标准看板。' },
38
+ argsHint: '数据源、使用人群、希望解决的问题、时间范围(可选)',
39
+ instructions: [newDashboard, discover, automaticTheme, metrics, standard, preview, receipt]
40
+ },
41
+ {
42
+ name: 'dashboard-standard-new', group: 'standard',
43
+ label: { en_US: 'Standard · Create for a topic', zh_Hans: '标准看板 · 指定主题新建' },
44
+ description: { en_US: 'Create a native dashboard for a specific business question.', zh_Hans: '围绕指定业务问题设计指标、趋势、对比、明细和筛选。' },
45
+ argsHint: '业务主题、数据源、使用人群、时间范围、必需指标',
46
+ instructions: [newDashboard, specifiedTheme, discover, metrics, standard, preview, receipt]
47
+ },
48
+ {
49
+ name: 'dashboard-standard-improve', group: 'standard',
50
+ label: { en_US: 'Standard · Improve a dashboard', zh_Hans: '标准看板 · 优化已有看板' },
51
+ description: { en_US: 'Improve the selected native dashboard while preserving its identity.', zh_Hans: '调整指定标准看板的图表、指标或筛选,保留原看板身份。' },
52
+ argsHint: '选中的看板或准确名称、需要调整的图表/指标/筛选',
53
+ instructions: [existing, 'Require a standard presentation. If the target is HTML, explain the mismatch rather than converting it. Edit only supported definition fields and omit htmlPath/libraries. Use dashboard_update, not a creation tool.', metrics, preview, receipt]
54
+ },
55
+ {
56
+ name: 'dashboard-standard-recover', group: 'standard',
57
+ label: { en_US: 'Standard · Recover a save', zh_Hans: '标准看板 · 恢复保存' },
58
+ description: { en_US: 'Diagnose a failed native draft save and resume with fresh evidence.', zh_Hans: '定位标准看板保存错误,按本轮真实验证结果恢复草稿保存。' },
59
+ argsHint: '失败工具及原始错误、新建还是修改、目标看板(如有)',
60
+ instructions: [recovery, 'Keep standard mode. For a failed new creation use dashboard_create after checking for an existing successful save. Do not create HTML files or call dashboard_create_html. If the existing target is HTML, report the mismatch instead of converting it.', `Only when recovering an existing Artifact: ${existing}`, metrics, preview, receipt]
61
+ },
62
+ {
63
+ name: 'dashboard-html-auto', group: 'html',
64
+ label: { en_US: 'HTML · Choose a business theme', zh_Hans: 'HTML 看板 · 自动选题新建' },
65
+ description: { en_US: 'Choose an actionable business theme and build a polished independent HTML dashboard.', zh_Hans: '选择有真实业务价值的数据,创建布局精致、可实际使用的 HTML 看板。' },
66
+ argsHint: '数据源、使用人群、业务目标、时间范围、风格(可选)',
67
+ instructions: [newDashboard, discover, automaticTheme, metrics, preview, html, design, receipt]
68
+ },
69
+ {
70
+ name: 'dashboard-html-new', group: 'html',
71
+ label: { en_US: 'HTML · Create for a topic', zh_Hans: 'HTML 看板 · 指定主题新建' },
72
+ description: { en_US: 'Build a custom live HTML page for a specific business decision.', zh_Hans: '围绕指定业务问题制作自定义 HTML 看板,保留真实查询与交互。' },
73
+ argsHint: '业务主题、数据源、使用人群、日期、必需指标、风格/参考图',
74
+ instructions: [newDashboard, specifiedTheme, discover, metrics, preview, html, design, receipt]
75
+ },
76
+ {
77
+ name: 'dashboard-html-style', group: 'html',
78
+ label: { en_US: 'HTML · Style from a reference', zh_Hans: 'HTML 看板 · 参考图片美化' },
79
+ description: { en_US: 'Restyle a selected HTML dashboard using a reference without fabricating business content.', zh_Hans: '参考图片或风格描述美化指定 HTML 看板,保留指标、绑定和功能。' },
80
+ argsHint: '目标 HTML 看板、参考图片或风格描述、希望改善的地方',
81
+ instructions: [existing, 'Require an HTML target. Read the returned htmlPath editing copy and dashboard_libraries runtime contract; save with dashboard_update using that exact editing path. Use the reference for hierarchy, layout, typography and visual rhythm, not its example data, unsupported widgets or invented business events. If no usable reference/style was supplied, ask for the missing input. Preserve query/subscription/filter/refresh behavior and dependency locks for style-only work; do not rebuild unchanged queries or require fresh previews for unchanged Bindings.', design, receipt]
82
+ },
83
+ {
84
+ name: 'dashboard-html-recover', group: 'html',
85
+ label: { en_US: 'HTML · Recover a save', zh_Hans: 'HTML 看板 · 恢复保存' },
86
+ description: { en_US: 'Resume an unsaved HTML candidate or draft using actual validation diagnostics.', zh_Hans: '保留已有页面与真实查询,定位运行校验问题并恢复保存。' },
87
+ argsHint: '失败工具和原始错误、HTML 文件路径、目标看板(如有)',
88
+ instructions: [recovery, 'Keep HTML mode. Read the existing candidate instead of rewriting it. For a new unsaved candidate, use its verified path with dashboard_create_html after checking prior save outcomes. For an existing HTML Artifact, save the current editing copy with dashboard_update. If the target is standard, report the mismatch instead of converting it. Read dashboard_libraries and the skill HTML lifecycle reference before a targeted page repair.', `Only when recovering an existing Artifact: ${existing}`, metrics, preview, receipt]
89
+ },
90
+ {
91
+ name: 'dashboard-explore', group: 'checks',
92
+ label: { en_US: 'Inspect · Explore sources', zh_Hans: '通用检查 · 探索数据源' },
93
+ description: { en_US: 'Inspect available sources and propose useful themes without creating resources.', zh_Hans: '只读检查来源、字段、数据新鲜度,推荐可用的业务主题。' },
94
+ argsHint: '指定来源或业务方向、关注的问题(可选)',
95
+ instructions: ['This is inspection only: do not register definitions, write files, create or update dashboards. Call dashboard_list_sources, inspect relevant contracts with dashboard_discover and use small bounded previews. If a source is missing, inspect available analytics_definition_connections/analytics_definition_inspect without registration.', metrics, 'Return a short source inventory with supported queries, date coverage and gaps, then up to three ranked business themes with audience, decision, useful metrics and readiness. No exhaustive database scan.']
96
+ },
97
+ {
98
+ name: 'dashboard-test-source', group: 'checks',
99
+ label: { en_US: 'Inspect · Test a source', zh_Hans: '通用检查 · 验证查询' },
100
+ description: { en_US: 'Run a minimal real query and filter acceptance for one source.', zh_Hans: '验证一个来源的发现、真实查询、字段映射和筛选链路。' },
101
+ argsHint: '数据源名称、一个业务指标、一个筛选维度(可选)',
102
+ instructions: ['This is a bounded read-only source test: do not register definitions, write files or save dashboards. Resolve the requested source with dashboard_list_sources and dashboard_discover. Preview one minimal real query; inspect field types, units, completeness and actual rows. Test one observed non-default filter and the all-values/null case when supported using dashboard_test_filter. Stop at the first unresolved failure. Report exact tool/error, the step that passed and the remaining gap; provider connectivity alone is not full dashboard acceptance.']
103
+ },
104
+ {
105
+ name: 'dashboard-audit-metrics', group: 'checks',
106
+ label: { en_US: 'Inspect · Audit metric definitions', zh_Hans: '通用检查 · 核对指标口径' },
107
+ description: { en_US: 'Check calculations, grain and comparisons without changing the dashboard.', zh_Hans: '检查分子分母、去重、关联粒度、统计期间与单位。' },
108
+ argsHint: '目标看板或数据源、需要核对的指标及已知业务口径',
109
+ instructions: ['Audit only. Inspect the selected/uniquely identified dashboard with dashboard_open, or resolve the supplied source with dashboard_list_sources/dashboard_discover. Do not register definitions, edit files or save changes. Use bounded independent previews to check the declared calculations against source data.', metrics, 'Return each metric with its actual formula, grain, period, unit, evidence and verdict: verified, incorrect or insufficient evidence. Distinguish business-definition uncertainty from a query defect. Recommend concrete corrections without applying them.']
110
+ },
111
+ {
112
+ name: 'dashboard-verify', group: 'checks',
113
+ label: { en_US: 'Inspect · Verify a saved dashboard', zh_Hans: '通用检查 · 验证筛选与刷新' },
114
+ description: { en_US: 'Verify saved identity, real filters and refresh; distinguish viewer checks from tool evidence.', zh_Hans: '核对保存版本、筛选与刷新,区分真实执行证据和待人工验证项。' },
115
+ argsHint: '目标看板、筛选场景、预期业务结果(可选)',
116
+ instructions: ['Acceptance only. Resolve the exact requested Artifact, open its current saved state with dashboard_open and record its identity/revision. Do not modify files, call save tools, publish or change source data. Preview its saved Bindings with actual defaults and observed alternative filter values; use dashboard_test_filter to validate affected queries and the null/all case. For HTML inspect its saved lifecycle and dependency contract as well. If actual viewer controls can be exercised through available authorized tools, check initial load, apply filters, refresh and reopening. Otherwise mark viewer behavior untested and give at most three manual actions with observable expected results. Do not equate a successful query or resource card with a verified browser interaction.']
117
+ }
118
+ ].map(command);