@shwfed/config 2.3.10 → 2.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/mcp.mjs +946 -544
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{config-CyScbxXy.js → config-B-1L3Ra-.js} +1 -1
  4. package/dist/preview/assets/{config-ja_GMXxV.js → config-Cf5kO84H.js} +1 -1
  5. package/dist/preview/assets/{config-bxqg3yuv.js → config-DTQkLHVw.js} +1 -1
  6. package/dist/preview/assets/{config-HdWYFZ09.js → config-DqxN0Byp.js} +1 -1
  7. package/dist/preview/assets/{config-2R4XkSGs.js → config-QUQ71Eo6.js} +1 -1
  8. package/dist/preview/assets/{config-ykJZssgx.js → config-oO93sSer.js} +1 -1
  9. package/dist/preview/assets/{config-KcLrpkc1.js → config-sJ5XKUJy.js} +1 -1
  10. package/dist/preview/assets/{config-BxzDT_57.js → config-zCMkbPQt.js} +1 -1
  11. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-CWyVRSOh.js → definition.vue_vue_type_script_setup_true_lang-D-OVRv68.js} +1 -1
  12. package/dist/preview/assets/index-Br_eXThF.css +1 -0
  13. package/dist/preview/assets/index-D8QyOVfp.js +637 -0
  14. package/dist/preview/assets/index-b_t8yWJJ.js +1 -0
  15. package/dist/preview/assets/{runtime-B8aUJIpn.js → runtime-10_7L7Gz.js} +1 -1
  16. package/dist/preview/assets/{runtime-CxA8fvQP.js → runtime-B2EP6060.js} +1 -1
  17. package/dist/preview/assets/{runtime-LBdh1D75.js → runtime-BxlgShjU.js} +1 -1
  18. package/dist/preview/assets/{runtime-DqZhDPHl.js → runtime-Cv2doZNu.js} +1 -1
  19. package/dist/preview/assets/{runtime-CpSiaWMP.js → runtime-CzDUrqSa.js} +1 -1
  20. package/dist/preview/assets/{runtime-D2K1s33u.js → runtime-DcYhXvSk.js} +1 -1
  21. package/dist/preview/assets/{runtime-DAXQmtLg.js → runtime-DlDhRVII.js} +1 -1
  22. package/dist/preview/assets/{runtime-C9XnvD5A.js → runtime-cmkN6aik.js} +1 -1
  23. package/dist/preview/index.html +2 -2
  24. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +1 -1
  25. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/schema.d.ts +4 -0
  26. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/schema.js +6 -17
  27. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +18 -18
  28. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +18 -18
  29. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.d.vue.ts +4 -4
  30. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.vue.d.ts +4 -4
  31. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +22 -22
  32. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +22 -22
  33. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.time/config.d.vue.ts +2 -2
  34. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.time/config.vue.d.ts +2 -2
  35. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +4 -4
  36. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +4 -4
  37. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.d.vue.ts +12 -12
  38. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.vue.d.ts +12 -12
  39. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.switch/config.d.vue.ts +10 -10
  40. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.switch/config.vue.d.ts +10 -10
  41. package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.d.vue.ts +12 -12
  42. package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue.d.ts +12 -12
  43. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +133 -0
  44. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue +605 -0
  45. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +133 -0
  46. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.d.vue.ts +8 -0
  47. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.vue +324 -0
  48. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.vue.d.ts +8 -0
  49. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/schema.d.ts +99 -0
  50. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/schema.js +129 -0
  51. package/dist/runtime/components/form/unit-config.vue +8 -27
  52. package/dist/runtime/components/form/utils/resolve.d.ts +48 -9
  53. package/dist/runtime/components/form/utils/resolve.js +59 -5
  54. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/config.d.vue.ts +10 -0
  55. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/config.vue +305 -0
  56. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/config.vue.d.ts +10 -0
  57. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.d.vue.ts +9 -0
  58. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.vue +81 -0
  59. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.vue.d.ts +9 -0
  60. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/schema.d.ts +55 -0
  61. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/schema.js +82 -0
  62. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/config.d.vue.ts +10 -0
  63. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/config.vue +310 -0
  64. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/config.vue.d.ts +10 -0
  65. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.d.vue.ts +9 -0
  66. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.vue +81 -0
  67. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.vue.d.ts +9 -0
  68. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/schema.d.ts +66 -0
  69. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/schema.js +71 -0
  70. package/dist/runtime/components/table/config.d.vue.ts +2 -2
  71. package/dist/runtime/components/table/config.vue +7 -46
  72. package/dist/runtime/components/table/config.vue.d.ts +2 -2
  73. package/dist/runtime/components/table/schema.d.ts +9 -2
  74. package/dist/runtime/components/table/schema.js +30 -14
  75. package/dist/runtime/components/table/utils/resolve.d.ts +53 -0
  76. package/dist/runtime/components/table/utils/resolve.js +66 -1
  77. package/dist/runtime/components/ui/date-range-picker/DateRangePickerDateTimePanel.d.vue.ts +1 -1
  78. package/dist/runtime/components/ui/date-range-picker/DateRangePickerDateTimePanel.vue.d.ts +1 -1
  79. package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +1 -1
  80. package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +1 -1
  81. package/dist/runtime/components/ui/tree/Tree.d.vue.ts +57 -0
  82. package/dist/runtime/components/ui/tree/Tree.vue +325 -0
  83. package/dist/runtime/components/ui/tree/Tree.vue.d.ts +57 -0
  84. package/dist/runtime/components/ui/tree/TreeNode.d.vue.ts +53 -0
  85. package/dist/runtime/components/ui/tree/TreeNode.vue +299 -0
  86. package/dist/runtime/components/ui/tree/TreeNode.vue.d.ts +53 -0
  87. package/dist/runtime/components/ui/tree/index.d.ts +3 -0
  88. package/dist/runtime/components/ui/tree/index.js +2 -0
  89. package/dist/runtime/components/ui/tree/types.d.ts +120 -0
  90. package/dist/runtime/components/ui/tree/types.js +0 -0
  91. package/dist/runtime/components/ui/tree/useTreeState.d.ts +95 -0
  92. package/dist/runtime/components/ui/tree/useTreeState.js +369 -0
  93. package/dist/runtime/shims.d.ts +2 -0
  94. package/package.json +1 -1
  95. package/dist/preview/assets/index-BPKK3hGV.css +0 -1
  96. package/dist/preview/assets/index-D3pf2RjG.js +0 -1
  97. package/dist/preview/assets/index-OUd02U3g.js +0 -1075
  98. package/dist/runtime/components/form/ai/fields-button.d.vue.ts +0 -13
  99. package/dist/runtime/components/form/ai/fields-button.vue +0 -458
  100. package/dist/runtime/components/form/ai/fields-button.vue.d.ts +0 -13
  101. package/dist/runtime/components/form/ai/fields-task.md +0 -71
  102. package/dist/runtime/components/table/ai/columns-button.d.vue.ts +0 -12
  103. package/dist/runtime/components/table/ai/columns-button.vue +0 -491
  104. package/dist/runtime/components/table/ai/columns-button.vue.d.ts +0 -12
  105. package/dist/runtime/components/table/ai/columns-task.md +0 -53
  106. package/dist/runtime/components/table/ai/data-source-button.d.vue.ts +0 -20
  107. package/dist/runtime/components/table/ai/data-source-button.vue +0 -324
  108. package/dist/runtime/components/table/ai/data-source-button.vue.d.ts +0 -20
  109. package/dist/runtime/components/table/ai/data-source-task.md +0 -17
  110. package/dist/runtime/utils/ai/cel-prompt.d.ts +0 -11
  111. package/dist/runtime/utils/ai/cel-prompt.js +0 -27
@@ -1,491 +0,0 @@
1
- <script setup>
2
- import { celCheck as $celCheck } from "../../../utils/cel";
3
- import { Icon } from "@iconify/vue";
4
- import { Either, ParseResult, Schema } from "effect";
5
- import { computed, ref } from "vue";
6
- import { toast } from "vue-sonner";
7
- import ShwfedModal from "../../modal.vue";
8
- import { Button } from "../../ui/button";
9
- import { InputGroupButton } from "../../ui/input-group";
10
- import { Markdown } from "../../ui/markdown";
11
- import { Textarea } from "../../ui/textarea";
12
- import { Tooltip, TooltipContent, TooltipTrigger } from "../../ui/tooltip";
13
- import { composeCelPrompt } from "../../../utils/ai/cel-prompt";
14
- import { StructuredOutputDecodeError, ai as $ai } from "../../../utils/ai";
15
- import { COLUMNS, findColumn } from "../utils/resolve";
16
- import TASK from "./columns-task.md?raw";
17
- defineOptions({ name: "ShwfedTableAiColumnsButton" });
18
- const props = defineProps({
19
- dataSource: { type: Object, required: false },
20
- columns: { type: Array, required: false }
21
- });
22
- const emit = defineEmits(["apply"]);
23
- const LocaleEntry = Schema.Struct({
24
- locale: Schema.String,
25
- message: Schema.String
26
- }).annotations({ identifier: "LocaleEntry" });
27
- const ColumnDraft = Schema.Struct({
28
- id: Schema.optional(Schema.String).annotations({
29
- description: "Stable column id. Reuse the existing id when the described column clearly maps onto an existing one (pinning state references it). For brand-new columns, call the `gen_uuid` tool to obtain a fresh id \u2014 do NOT invent UUIDs yourself. (If omitted entirely the host mints a fallback UUID, but always prefer `gen_uuid`.)"
30
- }),
31
- type: Schema.String.annotations({
32
- description: 'Column type \u2014 must match a `type` listed under "Available column types" in the system prompt.'
33
- }),
34
- compatibilityDate: Schema.String.annotations({
35
- description: "Compatibility date for the column type \u2014 copy verbatim from the matching registry entry."
36
- }),
37
- groupId: Schema.optional(Schema.String),
38
- title: Schema.optional(Schema.Array(LocaleEntry)).annotations({
39
- description: 'Localized column title, e.g. [{"locale":"zh","message":"\u59D3\u540D"}].'
40
- }),
41
- accessor: Schema.optional(Schema.String).annotations({
42
- description: "CEL expression returning the cell value. Bound variables: row (dyn), index (number), id (string)."
43
- }),
44
- size: Schema.optional(Schema.Number),
45
- grow: Schema.optional(Schema.Boolean),
46
- enableSorting: Schema.optional(Schema.Boolean),
47
- align: Schema.optional(Schema.String),
48
- tooltip: Schema.optional(Schema.Array(LocaleEntry)),
49
- copyExpression: Schema.optional(Schema.String).annotations({
50
- description: "CEL expression returning a string to copy on click."
51
- }),
52
- displayMode: Schema.optional(Schema.String),
53
- preserveMode: Schema.optional(Schema.String),
54
- preserveDigits: Schema.optional(Schema.Number),
55
- format: Schema.optional(Schema.String),
56
- color: Schema.optional(Schema.String),
57
- mode: Schema.optional(Schema.String),
58
- crossPage: Schema.optional(Schema.Boolean),
59
- enableRowSelection: Schema.optional(Schema.String),
60
- enableMultiRowSelection: Schema.optional(Schema.String),
61
- markdown: Schema.optional(Schema.Array(LocaleEntry)).annotations({
62
- description: "Localized markdown body with {{ CEL }} interpolations bound to row/index/id."
63
- })
64
- });
65
- const ColumnsDraft = Schema.Struct({
66
- columns: Schema.Array(ColumnDraft).annotations({
67
- description: "FULL replacement for the columns array. Emit every column the user described, in render order. The host does NOT merge with the previous configuration \u2014 columns you omit are removed."
68
- })
69
- });
70
- const ROW_SCOPE = {
71
- row: { type: "dyn", label: "\u5F53\u524D\u884C", description: "\u5F53\u524D\u6E32\u67D3\u7684\u6574\u884C\u6570\u636E\uFF1B\u7C7B\u578B\u5728\u914D\u7F6E\u65F6\u672A\u77E5\uFF08dyn\uFF09", value: void 0 },
72
- index: { type: "number", label: "\u884C\u5E8F\u53F7", description: "\u5F53\u524D\u884C\u5728\u6240\u6709\u6570\u636E\u4E2D\u7684\u5E8F\u53F7\uFF0C\u4ECE 0 \u5F00\u59CB", value: 0 },
73
- id: { type: "string", label: "\u5217 ID", description: "\u5F53\u524D\u5355\u5143\u683C\u6240\u5728\u5217\u7684 id", value: "" }
74
- };
75
- const PROHIBITED_TYPE = "com.shwfed.table.column.actions";
76
- const REQUIRES_EXPLICIT_TYPE = "com.shwfed.table.column.markdown";
77
- function renderRegisterables() {
78
- const lines = [];
79
- lines.push("# Available column types");
80
- lines.push("");
81
- for (const entry of COLUMNS) {
82
- if (entry.type === PROHIBITED_TYPE) continue;
83
- const fields = describeColumnFields(entry.type);
84
- lines.push(`## \`${entry.type}\` (compatibilityDate \`${entry.compatibilityDate}\`)`);
85
- lines.push("");
86
- lines.push(`Renders: ${entry.metadata.name}.`);
87
- if (entry.type === REQUIRES_EXPLICIT_TYPE) {
88
- lines.push("");
89
- lines.push("**Only emit this when the user explicitly asks for markdown / rich content / formatted body / \u5BCC\u6587\u672C.**");
90
- }
91
- lines.push("");
92
- lines.push(fields);
93
- lines.push("");
94
- }
95
- return lines.join("\n");
96
- }
97
- function describeColumnFields(type) {
98
- const common = [
99
- "- `id` (string, recommended): stable column id; reuse the existing id when the described column maps onto an existing one.",
100
- '- `title` (locale array): `[{ "locale": "zh", "message": "..." }]`.',
101
- "- `accessor` (CEL string): expression returning the cell value, given `row`, `index`, `id`.",
102
- "- `size` (number, optional), `grow` (bool, optional), `enableSorting` (bool, optional).",
103
- "- `tooltip` (locale array, optional), `copyExpression` (CEL string, optional).",
104
- '- `align`: one of `"left" | "center" | "right"`.'
105
- ];
106
- switch (type) {
107
- case "com.shwfed.table.column.text":
108
- return [
109
- ...common,
110
- '- `displayMode`: `"plain"` (default) or `"mono"` for monospace.'
111
- ].join("\n");
112
- case "com.shwfed.table.column.number":
113
- return [
114
- ...common,
115
- '- `displayMode`: `"plain"` | `"uppercaseChinese"` | `"monoThousand"`.',
116
- '- `preserveMode` (optional): `"round" | "floor" | "ceil"`.',
117
- "- `preserveDigits` (optional, non-negative integer)."
118
- ].join("\n");
119
- case "com.shwfed.table.column.date":
120
- return [
121
- ...common,
122
- '- `format` (string, required): Unicode date pattern, e.g. `"yyyy-MM-dd"` or `"yyyy-MM-dd HH:mm:ss"`.'
123
- ].join("\n");
124
- case "com.shwfed.table.column.icon":
125
- return [
126
- ...common,
127
- "- `accessor`: CEL returning an Iconify identifier (e.g. `row.iconName`).",
128
- "- `color` (CEL string, optional): expression returning a CSS color."
129
- ].join("\n");
130
- case "com.shwfed.table.column.select":
131
- return [
132
- "- `id` (string, recommended).",
133
- '- `mode`: `"radio"` (single) or `"checkbox"` (default, multi).',
134
- "- `crossPage` (bool, optional): remember selection across pages.",
135
- "- `enableRowSelection` / `enableMultiRowSelection` (CEL string, optional): predicates over `row`/`index` returning bool.",
136
- "- No `accessor` / `title` \u2014 selection is rendered with a checkbox header."
137
- ].join("\n");
138
- case "com.shwfed.table.column.markdown":
139
- return [
140
- "- `id` (string, recommended).",
141
- "- `title` (locale array): column header.",
142
- "- `markdown` (locale array, required): body content per locale; supports `{{ CEL }}` interpolation referencing `row`, `index`, `id`.",
143
- "- `size` / `grow` / `tooltip` / `copyExpression`: same as common.",
144
- "- No `accessor` (rendered content comes from `markdown`)."
145
- ].join("\n");
146
- default:
147
- return common.join("\n");
148
- }
149
- }
150
- const open = ref(false);
151
- const context = ref("");
152
- const submitting = ref(false);
153
- const tick = ref(0);
154
- const description = [
155
- "\u63CF\u8FF0\u4F60\u60F3\u8981\u7684**\u5B8C\u6574\u5217\u5E03\u5C40**\uFF0C\u53EF\u9644\u793A\u4F8B\u54CD\u5E94\u3001\u5B57\u6BB5\u542B\u4E49\u6216 PRD\u3002",
156
- "",
157
- "AI \u4F1A**\u6574\u5217\u66FF\u6362**\u5F53\u524D\u7684\u5217\u914D\u7F6E \u2014 \u672A\u5728\u63CF\u8FF0\u4E2D\u63D0\u5230\u7684\u5217\u4F1A\u88AB\u79FB\u9664\uFF0C\u8BF7\u628A\u6240\u6709\u9700\u8981\u4FDD\u7559\u7684\u5217\u4E5F\u4E00\u5E76\u63CF\u8FF0\u51FA\u6765\u3002"
158
- ].join("\n");
159
- const canSubmit = computed(() => !submitting.value && context.value.trim().length > 0);
160
- function onTrigger() {
161
- open.value = true;
162
- }
163
- const CEL_FIELDS_BY_TYPE = {
164
- "com.shwfed.table.column.text": ["accessor", "copyExpression"],
165
- "com.shwfed.table.column.number": ["accessor", "copyExpression"],
166
- "com.shwfed.table.column.date": ["accessor", "copyExpression"],
167
- "com.shwfed.table.column.icon": ["accessor", "color"],
168
- "com.shwfed.table.column.select": ["enableRowSelection", "enableMultiRowSelection"],
169
- "com.shwfed.table.column.markdown": ["copyExpression"]
170
- };
171
- function checkCelString(expr) {
172
- if (typeof expr !== "string" || expr.trim() === "") return null;
173
- const checked = $celCheck(expr);
174
- if (Either.isLeft(checked)) {
175
- return checked.left instanceof Error ? checked.left.message : String(checked.left);
176
- }
177
- return null;
178
- }
179
- function collectErrors(cols) {
180
- const out = [];
181
- cols.forEach((col, i) => {
182
- const prefix = `columns[${i}]`;
183
- if (col.type === PROHIBITED_TYPE) {
184
- out.push({
185
- path: prefix,
186
- message: `Column type "${PROHIBITED_TYPE}" is prohibited. Drop this column entirely \u2014 action columns are wired by a separate registry.`
187
- });
188
- return;
189
- }
190
- const entry = findColumn(col.type, col.compatibilityDate);
191
- if (!entry) {
192
- out.push({
193
- path: `${prefix}.type`,
194
- message: `Unknown column type "${col.type}@${col.compatibilityDate}". Use one of the registered types listed in the system prompt.`
195
- });
196
- return;
197
- }
198
- const perTypeSchema = entry.schema(() => {
199
- });
200
- const decoded = Schema.decodeUnknownEither(perTypeSchema)(col);
201
- if (Either.isLeft(decoded)) {
202
- const issues = ParseResult.ArrayFormatter.formatErrorSync(decoded.left);
203
- for (const issue of issues) {
204
- const sub = issue.path.map(String).join(".");
205
- out.push({
206
- path: sub ? `${prefix}.${sub}` : prefix,
207
- message: issue.message
208
- });
209
- }
210
- }
211
- for (const field of CEL_FIELDS_BY_TYPE[col.type] ?? []) {
212
- const msg = checkCelString(col[field]);
213
- if (msg) out.push({ path: `${prefix}.${field}`, message: msg });
214
- }
215
- });
216
- return out;
217
- }
218
- function buildRetryFeedback(errors) {
219
- const lines = errors.map(({ path, message }) => `- \`${path}\`: ${message}`);
220
- return [
221
- "The previous output failed validation. Fix only the listed paths and return the corrected object \u2014 keep the other fields identical.",
222
- "",
223
- "Reminders:",
224
- `- NEVER emit a column with type "${PROHIBITED_TYPE}".`,
225
- `- ONLY emit a column with type "${REQUIRES_EXPLICIT_TYPE}" when the user explicitly asks for markdown / rich content.`,
226
- "- The `columns` array is a full replacement; emit every column the user described.",
227
- "",
228
- "Errors:",
229
- ...lines
230
- ].join("\n");
231
- }
232
- function buildShapeFeedback(message) {
233
- return [
234
- "The previous output did not match the required JSON shape. Re-emit the structured output, this time matching the schema exactly. The output must be a JSON object with a required `columns` array. Each column needs at minimum `type` and `compatibilityDate`.",
235
- "",
236
- "Decoder error:",
237
- message
238
- ].join("\n");
239
- }
240
- function tryUnwrap(raw) {
241
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
242
- const entries = Object.entries(raw);
243
- if (entries.length !== 1) return null;
244
- const [, inner] = entries[0];
245
- let candidate = inner;
246
- if (typeof candidate === "string") {
247
- try {
248
- candidate = JSON.parse(candidate);
249
- } catch {
250
- return null;
251
- }
252
- }
253
- if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return null;
254
- if (!("columns" in candidate)) return null;
255
- return candidate;
256
- }
257
- const genUuidTool = {
258
- name: "gen_uuid",
259
- description: "Generate a fresh RFC 4122 UUID string. Call this whenever you need an `id` for a new column. Returns the UUID directly as a plain string \u2014 use the returned value verbatim. Never invent UUIDs yourself; call this tool instead.",
260
- inputJsonSchema: { type: "object", properties: {}, additionalProperties: false },
261
- execute: () => crypto.randomUUID()
262
- };
263
- async function callModel(prompt, system, retry) {
264
- try {
265
- const value = await $ai.generateObject({
266
- prompt,
267
- system,
268
- schema: ColumnsDraft,
269
- objectName: "columns",
270
- tools: [genUuidTool],
271
- ...retry ? { retry } : {},
272
- onProgress: () => {
273
- tick.value++;
274
- }
275
- });
276
- const errors = collectErrors(value.columns);
277
- if (errors.length > 0) {
278
- return { kind: "retry", previousOutput: value, feedback: buildRetryFeedback(errors) };
279
- }
280
- return { kind: "ok", value };
281
- } catch (err) {
282
- if (err instanceof StructuredOutputDecodeError) {
283
- const unwrapped = tryUnwrap(err.rawOutput);
284
- if (unwrapped !== null) {
285
- const decoded = Schema.decodeUnknownEither(ColumnsDraft)(unwrapped);
286
- if (Either.isRight(decoded)) {
287
- const value = decoded.right;
288
- const errors = collectErrors(value.columns);
289
- if (errors.length === 0) return { kind: "ok", value };
290
- return { kind: "retry", previousOutput: value, feedback: buildRetryFeedback(errors) };
291
- }
292
- }
293
- return { kind: "retry", previousOutput: err.rawOutput, feedback: buildShapeFeedback(err.message) };
294
- }
295
- throw err;
296
- }
297
- }
298
- const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
299
- function sanitizeColumn(col) {
300
- const raw = {};
301
- for (const [k, v] of Object.entries(col)) {
302
- if (v === void 0) continue;
303
- if (typeof v === "string" && v.trim() === "") continue;
304
- raw[k] = v;
305
- }
306
- const incomingId = typeof raw.id === "string" ? raw.id : void 0;
307
- raw.id = incomingId && UUID_RE.test(incomingId) ? incomingId : crypto.randomUUID();
308
- return raw;
309
- }
310
- function buildEmit(value) {
311
- return value.columns.filter((c) => c.type !== PROHIBITED_TYPE).map((c) => sanitizeColumn(c));
312
- }
313
- function buildUserPrompt() {
314
- return [
315
- context.value.trim(),
316
- "",
317
- "# Current configuration",
318
- "",
319
- "```json",
320
- // Knowing the data source informs row shape; knowing the existing columns
321
- // lets the model reuse stable ids where the described layout corresponds.
322
- JSON.stringify({
323
- dataSource: props.dataSource ?? null,
324
- columns: props.columns ?? []
325
- }, null, 2),
326
- "```"
327
- ].join("\n");
328
- }
329
- async function onSubmit() {
330
- if (!canSubmit.value) return;
331
- submitting.value = true;
332
- tick.value = 0;
333
- try {
334
- const baseSystem = composeCelPrompt({
335
- scope: [
336
- { name: "\u5217\u5185 CEL \u5B57\u6BB5\uFF08\u5982 `accessor`, `copyExpression`, `color`, `enableRowSelection` \u7B49\uFF09\u53EF\u7528\u53D8\u91CF", context: ROW_SCOPE }
337
- ],
338
- task: TASK
339
- });
340
- const system = `${baseSystem}
341
-
342
- ${renderRegisterables()}`;
343
- const prompt = buildUserPrompt();
344
- let outcome = await callModel(prompt, system);
345
- if (outcome.kind === "retry") {
346
- tick.value = 0;
347
- outcome = await callModel(prompt, system, {
348
- previousOutput: outcome.previousOutput,
349
- feedback: outcome.feedback
350
- });
351
- }
352
- if (outcome.kind === "ok") {
353
- const cols = buildEmit(outcome.value);
354
- if (cols.length > 0) {
355
- emit("apply", cols);
356
- toast.success("\u5DF2\u6839\u636E\u63CF\u8FF0\u751F\u6210\u5217");
357
- } else {
358
- toast.message("AI \u672A\u8FD4\u56DE\u4EFB\u4F55\u53EF\u5E94\u7528\u7684\u5217");
359
- }
360
- open.value = false;
361
- context.value = "";
362
- return;
363
- }
364
- const last = outcome.previousOutput;
365
- const candidate = last && typeof last === "object" ? last : null;
366
- const usable = candidate && "columns" in candidate ? candidate : tryUnwrap(last);
367
- if (usable && typeof usable === "object" && Array.isArray(usable.columns)) {
368
- const cols = buildEmit(usable);
369
- if (cols.length > 0) {
370
- emit("apply", cols);
371
- toast.message("AI \u8F93\u51FA\u672A\u901A\u8FC7\u6821\u9A8C\uFF0C\u5DF2\u5E94\u7528\u53EF\u89E3\u6790\u7684\u90E8\u5206\uFF0C\u8BF7\u68C0\u67E5");
372
- open.value = false;
373
- context.value = "";
374
- return;
375
- }
376
- }
377
- toast.error("AI \u751F\u6210\u5931\u8D25", { description: "\u6A21\u578B\u672A\u8FD4\u56DE\u53EF\u5E94\u7528\u7684\u5217\uFF0C\u8BF7\u8C03\u6574\u63CF\u8FF0\u540E\u91CD\u8BD5" });
378
- } catch (err) {
379
- const message = err instanceof Error ? err.message : String(err);
380
- toast.error("AI \u751F\u6210\u5931\u8D25", { description: message });
381
- } finally {
382
- submitting.value = false;
383
- }
384
- }
385
- </script>
386
-
387
- <template>
388
- <Tooltip :delay-duration="180">
389
- <TooltipTrigger as-child>
390
- <InputGroupButton
391
- size="icon-xs"
392
- variant="ghost"
393
- as-child
394
- >
395
- <button
396
- type="button"
397
- :disabled="submitting"
398
- class="-ml-4"
399
- @click="onTrigger"
400
- >
401
- <Icon
402
- icon="fluent:magic-wand-20-regular"
403
- class="size-4"
404
- />
405
- </button>
406
- </InputGroupButton>
407
- </TooltipTrigger>
408
- <TooltipContent side="top">
409
- AI 生成列
410
- </TooltipContent>
411
- </Tooltip>
412
-
413
- <ShwfedModal
414
- v-model:open="open"
415
- content-width="48rem"
416
- :dismissible="!submitting"
417
- >
418
- <template #title>
419
- <span class="flex items-center gap-2">
420
- <Icon
421
- icon="fluent:magic-wand-20-regular"
422
- class="size-5"
423
- />
424
- AI 生成列
425
- </span>
426
- </template>
427
- <template #description>
428
- <Markdown
429
- :source="description"
430
- block
431
- class="prose prose-sm prose-zinc max-w-none"
432
- />
433
- </template>
434
-
435
- <form
436
- class="flex flex-col gap-2 py-2"
437
- @submit.prevent="onSubmit"
438
- >
439
- <Textarea
440
- v-model="context"
441
- placeholder="任意上下文,建议包含:&#10;- 想要的列:例如「显示姓名、邮箱、注册时间」&#10;- 字段含义或示例响应(JSON)&#10;- 列宽 / 对齐 / 复制等额外要求"
442
- wrap="soft"
443
- class="field-sizing-fixed h-72 max-h-[60vh] resize-none overflow-auto break-all whitespace-pre-wrap font-mono text-xs"
444
- :disabled="submitting"
445
- />
446
- </form>
447
-
448
- <template #footer>
449
- <div class="flex items-center gap-2">
450
- <div
451
- v-if="submitting"
452
- class="mr-auto flex items-center gap-2 text-xs text-muted-foreground"
453
- aria-live="polite"
454
- >
455
- <span
456
- :key="tick"
457
- class="ai-progress-dot"
458
- :class="tick > 0 ? 'is-streaming' : 'is-waiting'"
459
- />
460
- <span>{{ tick > 0 ? "\u6B63\u5728\u63A5\u6536\u6A21\u578B\u8F93\u51FA\u2026" : "\u6B63\u5728\u8BF7\u6C42\u6A21\u578B\u2026" }}</span>
461
- </div>
462
- <Button
463
- type="button"
464
- size="sm"
465
- :disabled="submitting"
466
- @click="open = false"
467
- >
468
- <Icon icon="fluent:dismiss-20-regular" />
469
- 取消
470
- </Button>
471
- <Button
472
- type="button"
473
- variant="primary"
474
- size="sm"
475
- :disabled="!canSubmit"
476
- @click="onSubmit"
477
- >
478
- <Icon
479
- :icon="submitting ? 'fluent:arrow-sync-20-regular' : 'fluent:sparkle-20-regular'"
480
- :class="submitting ? 'animate-spin' : ''"
481
- />
482
- 生成
483
- </Button>
484
- </div>
485
- </template>
486
- </ShwfedModal>
487
- </template>
488
-
489
- <style scoped>
490
- .ai-progress-dot{background-color:var(--primary,currentColor);border-radius:9999px;display:inline-block;height:.5rem;width:.5rem}.ai-progress-dot.is-waiting{animation:ai-progress-waiting 1.2s ease-in-out infinite}.ai-progress-dot.is-streaming{animation:ai-progress-kick .32s ease-out}@keyframes ai-progress-waiting{0%,to{opacity:.35;transform:scale(1)}50%{opacity:1;transform:scale(1.15)}}@keyframes ai-progress-kick{0%{opacity:1;transform:scale(1.6)}to{opacity:.7;transform:scale(1)}}
491
- </style>
@@ -1,12 +0,0 @@
1
- type AnyRecord = Record<string, any>;
2
- type __VLS_Props = {
3
- dataSource?: AnyRecord;
4
- columns?: ReadonlyArray<AnyRecord>;
5
- };
6
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
- apply: (value: AnyRecord[]) => any;
8
- }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
9
- onApply?: ((value: AnyRecord[]) => any) | undefined;
10
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
- declare const _default: typeof __VLS_export;
12
- export default _default;
@@ -1,53 +0,0 @@
1
- Generate the **full columns array** for a table from the user's free-form description. The output is a single struct with one required field: `columns` — an array of column objects in render order.
2
-
3
- The `columns` array is a **full replacement**: whatever you emit becomes the entire column configuration. The host does **not** merge with the previous columns. Treat the user's prompt as the complete description of the desired layout, and emit every column they want in the final table, in render order.
4
-
5
- # Hard rules
6
-
7
- 1. **NEVER add** a new column with `type === "com.shwfed.table.column.actions"`. Action columns are wired by a separate registry — you cannot synthesize one, and a fabricated actions column will be rejected and you will be retried. The **one exception**: if the current configuration already contains an actions column, echo it back verbatim (same `id`, `type`, `compatibilityDate`, and all fields) in its render position. Never invent an actions column the user merely describes when none already exists.
8
- 2. **ONLY** emit a column with `type === "com.shwfed.table.column.markdown"` when the user **explicitly** asks for markdown / rich content / formatted body / 富文本 / Markdown. Otherwise prefer `com.shwfed.table.column.text`.
9
- 3. **NEVER** set `enableSorting: true`. Client-side sorting is rarely the right call in practice (paginated/server-driven data, mixed types, etc.) and the user should opt in manually. Omit the field or set it to `false`.
10
- 4. **NEVER** wrap the `accessor` in type coercions (`string(...)`, `int(...)`, `double(...)`) and **NEVER** supply a default via `.orValue(...)`. Emit the bare optional access — e.g. `row.?name`, `row.?age`. Coercion and defaults make it impossible for the user to distinguish real data from filler, which is actively harmful.
11
- - Correct: `row.?name`
12
- - Correct: `row.?age`
13
- - Wrong: `string(row.?name)`
14
- - Wrong: `double(row.?age.orValue(0))`
15
-
16
- # Column fields
17
-
18
- Each column object needs at minimum:
19
-
20
- - `id`: stable string. For new columns, call the `gen_uuid` tool to obtain an id — do **not** invent UUIDs yourself. If the user's described layout clearly maps onto an existing column from the current configuration (same role / accessor / field), reuse that column's `id` so pinning state survives — otherwise mint a fresh one via `gen_uuid`.
21
- - `type`: one of the registered types listed in "Available column types".
22
- - `compatibilityDate`: copy from the matching registry entry verbatim.
23
- - Type-specific fields (see registry).
24
-
25
- Common fields (where supported by the type):
26
- - `title`: localized string array, e.g. `[{ "locale": "zh", "message": "姓名" }]`. The `zh` entry is what users see in the Chinese UI.
27
- - `accessor`: CEL expression that, given the bound `row`, returns the cell value. Use bare optional access: `row.?name`. Do **not** add coercions or `.orValue(...)` defaults — see hard rule 4.
28
- - `size`: pixel column width (number).
29
- - `grow`: when true, the column stretches to fill remaining space.
30
- - `enableSorting`: client-side sorting flag. **Do not enable** — see hard rule 3.
31
- - `align`: `'left' | 'center' | 'right'`.
32
- - `tooltip`: localized markdown shown on header hover.
33
- - `copyExpression`: CEL returning a string to copy on click.
34
-
35
- The CEL `accessor` runs in a row-scoped environment with these variables:
36
- - `row` (`dyn`): current row data — shape depends on the data source.
37
- - `index` (`number`): row index.
38
- - `id` (`string`): the column's id.
39
-
40
- Always use optional access (`row.?field`) rather than `row.field` to avoid runtime errors on missing keys. Do **not** add type coercions or `.orValue(...)` defaults (see hard rule 4) — a missing/typed-wrong value should surface as missing, not be silently masked.
41
-
42
- If the user gives a sample response, derive accessors directly from its shape. Otherwise, infer field names from the user's prose (e.g. "show name and email" → `row.?name`, `row.?email`).
43
-
44
- # Rendering recipes
45
-
46
- **Boolean / `0`-`1` values.** When a field is a boolean or a `0`/`1` flag (e.g. `enabled`, `isActive`, a `0/1` status), render it with `com.shwfed.table.column.icon` rather than `text` — a green check / red cross reads far faster than the literal `true` or `1`. Build both the `accessor` and the `color` as CEL ternaries on the condition:
47
-
48
- - `accessor`: `<condition> ? 'fluent:checkmark-20-filled' : 'fluent:dismiss-20-filled'`
49
- - `color`: `<condition> ? '#00c950' : '#fb2c36'`
50
-
51
- where `<condition>` is a bare optional-access test — `row.?enabled == true` for a boolean field, `row.?status == 1` for a `0/1` field. This is a comparison, not a coercion, so hard rule 4 still holds: do not wrap in `string(...)`/`int(...)` or add `.orValue(...)`.
52
-
53
- The current configuration (existing data source + columns) is appended to the user prompt under `Current configuration`. Use it only to (a) reuse existing column `id`s where the user's described column clearly corresponds to an existing one, and (b) inform field shapes (e.g. response keys). Do **not** copy columns forward that the user did not describe — the user's prompt is the source of truth for which columns should exist.
@@ -1,20 +0,0 @@
1
- type AnyRecord = Record<string, any>;
2
- type __VLS_Props = {
3
- dataSource?: AnyRecord;
4
- columns?: ReadonlyArray<AnyRecord>;
5
- };
6
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
- apply: (value: {
8
- request?: string;
9
- data?: string;
10
- total?: string;
11
- }) => any;
12
- }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
- onApply?: ((value: {
14
- request?: string;
15
- data?: string;
16
- total?: string;
17
- }) => any) | undefined;
18
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
- declare const _default: typeof __VLS_export;
20
- export default _default;