openxiangda 1.0.36 → 1.0.38
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/README.md +10 -0
- package/lib/cli.js +43 -3
- package/lib/workspace-bootstrap.js +238 -0
- package/openxiangda-skills/SKILL.md +42 -3
- package/openxiangda-skills/references/pages/page-sdk.md +32 -0
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +348 -0
- package/openxiangda-skills/skills/openxiangda-app/SKILL.md +18 -2
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +37 -1
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +37 -2
- package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +26 -2
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +36 -2
- package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +19 -2
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +26 -2
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +114 -0
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +14 -1
- package/packages/sdk/dist/runtime/index.d.ts +14 -1
- package/packages/sdk/dist/runtime/index.mjs +114 -0
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-form.mdc +20 -0
- package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-page.mdc +19 -0
- package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-resources.mdc +28 -0
- package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-workflow-automation.mdc +21 -0
- package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda.mdc +47 -0
- package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-form.md +34 -0
- package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-page.md +37 -0
- package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-resources.md +46 -0
- package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-workflow-automation.md +46 -0
- package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda.md +47 -0
- package/templates/sy-lowcode-app-workspace/AGENTS.md +92 -0
- package/templates/sy-lowcode-app-workspace/package.json +7 -0
- package/templates/sy-lowcode-app-workspace/scripts/guard-publish.mjs +29 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Resource Manifest Cheatsheet
|
|
2
|
+
|
|
3
|
+
> 1-2 屏速查:`src/resources/` 下各类型 manifest 的最小可用模板与对应运行时调用方式。
|
|
4
|
+
> 这里只放"复制即用"的骨架;字段语义详见对应的 reference 文档。
|
|
5
|
+
|
|
6
|
+
## 通用约定
|
|
7
|
+
|
|
8
|
+
- **本地用逻辑 code**:所有 manifest 用稳定的 `formCode` / `pageCode` / `workflowCode` / `automationCode` / `connectorCode` / `dataViewCode` / `roleCode` / `notificationType`。
|
|
9
|
+
- **平台 ID 由 CLI 解析**:`openxiangda resource publish --profile <name>` 把 code 解析成当前 profile 的真实 ID 并写回 `.openxiangda/state.json`。
|
|
10
|
+
- **永远不写密钥**:第三方 API key、token、secret、password、authorization、headers 等绝不出现在 `src/resources/`,平台管理员在后台配置。
|
|
11
|
+
- **多 profile 不共享 ID**:`dev` / `prod` 各自维护一份资源 ID 映射,复制 manifest 即可复用,不要复制平台 ID。
|
|
12
|
+
|
|
13
|
+
## 命令
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
openxiangda resource validate --profile <name> # 静态校验所有 manifest
|
|
17
|
+
openxiangda resource plan --profile <name> # diff:本地 vs. 平台
|
|
18
|
+
openxiangda resource publish --profile <name> # 非破坏性 upsert(不 prune)
|
|
19
|
+
openxiangda resource publish --profile <name> --prune # 删除 manifest 未声明的平台资源(谨慎)
|
|
20
|
+
openxiangda resource pull --profile <name> # 拉取平台资源回写到本地(用于初次同步)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 1. Connector — `src/resources/connectors/<code>.json`
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"code": "crm",
|
|
28
|
+
"name": "CRM Service",
|
|
29
|
+
"url": "https://crm.internal.example.com/api",
|
|
30
|
+
"authType": "apiKey",
|
|
31
|
+
"authConfig": {
|
|
32
|
+
"apiKey": { "key": "X-API-Key", "value": "internal-secret", "in": "header" }
|
|
33
|
+
},
|
|
34
|
+
"userContext": {
|
|
35
|
+
"enabled": true,
|
|
36
|
+
"inject": [
|
|
37
|
+
{ "target": "header", "key": "X-User-Id", "value": "userId" },
|
|
38
|
+
{ "target": "body", "key": "operator", "value": "user" }
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"apis": [
|
|
42
|
+
{
|
|
43
|
+
"code": "getCustomer",
|
|
44
|
+
"name": "Get Customer",
|
|
45
|
+
"method": "POST",
|
|
46
|
+
"path": "/customers/search",
|
|
47
|
+
"requestBodyType": "json",
|
|
48
|
+
"responseType": "json"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
页面调用:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const data = await sdk.connector.call("crm.getCustomer", { body: { keyword } });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
不要把 `authConfig` 里的真实 secret 写进 manifest;用 placeholder,由平台管理员在后台覆盖。完整字段见 [`connector-resources.md`](connector-resources.md)。
|
|
61
|
+
|
|
62
|
+
## 2. Data View — `src/resources/data-views/<code>.json`
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"code": "ticket_with_customer",
|
|
67
|
+
"name": "Ticket With Customer",
|
|
68
|
+
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
69
|
+
"joins": [
|
|
70
|
+
{
|
|
71
|
+
"type": "left",
|
|
72
|
+
"formCode": "customer",
|
|
73
|
+
"alias": "customer",
|
|
74
|
+
"on": [
|
|
75
|
+
{ "left": "ticket.customer.value", "op": "=", "right": "customer.form_instance_id" }
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"select": [
|
|
80
|
+
{ "field": "ticket.form_instance_id", "as": "ticketId" },
|
|
81
|
+
{ "field": "ticket.title", "as": "ticketTitle" },
|
|
82
|
+
{ "field": "ticket.status.label", "as": "statusLabel" },
|
|
83
|
+
{ "field": "ticket.status.value", "as": "statusValue" },
|
|
84
|
+
{ "field": "customer.name", "as": "customerName" }
|
|
85
|
+
],
|
|
86
|
+
"indexes": [{ "fields": ["ticketId"], "unique": true }],
|
|
87
|
+
"refresh": { "mode": "scheduled", "cron": "0 */10 * * * *" },
|
|
88
|
+
"permissionGroups": [
|
|
89
|
+
{ "code": "ticket_query", "name": "Ticket Query", "roles": ["manager"], "operations": ["query"] }
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
页面调用:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const list = await sdk.dataView.query("ticket_with_customer", {
|
|
98
|
+
filters: [{ field: "statusValue", op: "in", values: ["open", "processing"] }],
|
|
99
|
+
order: [{ field: "ticketId", direction: "desc" }],
|
|
100
|
+
page: { current: 1, size: 20 },
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
适用:跨表只读联表 / 报表 / 大列表性能优化。**不适用**:单表 CRUD、`linkedForm` 下拉、强实时、写回。完整规则见 [`data-views.md`](data-views.md)。
|
|
105
|
+
|
|
106
|
+
## 3. Notification — `src/resources/notifications/<code>.json`
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"templates": [
|
|
111
|
+
{
|
|
112
|
+
"code": "reservation_reminder",
|
|
113
|
+
"name": "预约提醒",
|
|
114
|
+
"content": "{{title}}",
|
|
115
|
+
"variables": ["title", "instrumentName", "startTime"],
|
|
116
|
+
"channelsConfig": {
|
|
117
|
+
"inapp": { "enabled": true, "content": "{{instrumentName}} 将于 {{startTime}} 开始" },
|
|
118
|
+
"dingding": { "enabled": true, "content": "{{title}}" }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"typeConfigs": [
|
|
123
|
+
{
|
|
124
|
+
"notificationType": "reservation_reminder",
|
|
125
|
+
"templateCode": "reservation_reminder",
|
|
126
|
+
"enabled": true,
|
|
127
|
+
"priority": 0
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
页面调用:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
await sdk.notification.sendByType({
|
|
137
|
+
notificationType: "reservation_reminder",
|
|
138
|
+
recipientId: userId,
|
|
139
|
+
payload: { title: "预约提醒", instrumentName, startTime },
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
JS_CODE 调用:`ctx.notification.sendByType({ ... })`。允许的 channels:`inapp` / `email` / `dingding` / `wechat` / `thirdparty_todo`。完整规则见 [`notifications.md`](notifications.md)。
|
|
144
|
+
|
|
145
|
+
## 4. Workflow — `src/resources/workflows/<code>/workflow.json`(manifest)+ `src/workflows/<code>/workflow.ts`(代码优先)
|
|
146
|
+
|
|
147
|
+
```jsonc
|
|
148
|
+
// src/resources/workflows/customer_approval/workflow.json
|
|
149
|
+
{
|
|
150
|
+
"code": "customer_approval",
|
|
151
|
+
"formCode": "customer",
|
|
152
|
+
"kind": "workflow_v3",
|
|
153
|
+
"definitionFile": "definition.v3.json",
|
|
154
|
+
"previewFile": "preview.json"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
代码优先(推荐):
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
// src/workflows/customer_approval/workflow.ts
|
|
162
|
+
import { defineWorkflow } from "openxiangda/workflow";
|
|
163
|
+
|
|
164
|
+
export default defineWorkflow({
|
|
165
|
+
name: "客户审批",
|
|
166
|
+
trigger: { type: "form_submit", formCode: "customer" },
|
|
167
|
+
nodes: [
|
|
168
|
+
/* approval / copy / branch / js_code 节点 */
|
|
169
|
+
],
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
CLI 编译为 `definition.v3.json` + `preview.json`,平台运行时仍走标准工作流引擎。完整规则见 [`workflow-v3.md`](workflow-v3.md)。
|
|
174
|
+
|
|
175
|
+
## 5. Automation — `src/resources/automations/<code>/{definition.code.json,preview.json}` + `src/automations/<code>/index.ts`
|
|
176
|
+
|
|
177
|
+
```jsonc
|
|
178
|
+
// src/resources/automations/notify_on_submit/definition.code.json
|
|
179
|
+
{
|
|
180
|
+
"code": "notify_on_submit",
|
|
181
|
+
"name": "提交后通知",
|
|
182
|
+
"kind": "automation_code_ts",
|
|
183
|
+
"trigger": {
|
|
184
|
+
"version": 2,
|
|
185
|
+
"mode": "event",
|
|
186
|
+
"event": { "source": "form_data", "action": "submitted" },
|
|
187
|
+
"filters": { "formCode": "customer" }
|
|
188
|
+
},
|
|
189
|
+
"sourceFile": { "localPath": "src/automations/notify_on_submit/index.ts" },
|
|
190
|
+
"previewFile": "preview.json",
|
|
191
|
+
"timeout": 30000
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
// src/automations/notify_on_submit/index.ts
|
|
197
|
+
export default async function (ctx) {
|
|
198
|
+
ctx.logger.info("automation start", { formCode: ctx.formData.current.formCode });
|
|
199
|
+
await ctx.notification.sendByType({
|
|
200
|
+
notificationType: "submission_notice",
|
|
201
|
+
recipientId: ctx.operator.userId,
|
|
202
|
+
payload: { /* ... */ },
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`trigger_v2` 事件源:`form_data` / `form_field` / `workflow_task` / `workflow_process` / `mode: "scheduled"`(fixed_time / form_date_field)。完整规则见 [`automation-v3.md`](automation-v3.md)。
|
|
208
|
+
|
|
209
|
+
## 6. JS_CODE V2 — `src/js-code-nodes/<scriptCode>/index.ts`
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
export default async function (ctx) {
|
|
213
|
+
const { formData, operator, methods, notification, platform, utils, console } = ctx;
|
|
214
|
+
const result = await methods.queryManyData({
|
|
215
|
+
formCode: "customer",
|
|
216
|
+
formUuid: ctx.app.formUuids.customer,
|
|
217
|
+
searchCondition: [/* 查询条件 */],
|
|
218
|
+
});
|
|
219
|
+
return { count: result.length };
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
工作流 / 自动化 v3 JSON 节点引用:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"id": "sync_customer",
|
|
228
|
+
"type": "js_code",
|
|
229
|
+
"data": {
|
|
230
|
+
"label": "同步客户",
|
|
231
|
+
"runtimeMode": "trusted_node",
|
|
232
|
+
"sourceType": "file_snapshot",
|
|
233
|
+
"scriptCode": "sync_customer",
|
|
234
|
+
"sourceFile": { "localPath": "src/js-code-nodes/sync_customer/index.ts" },
|
|
235
|
+
"timeout": 30000
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
构建:`pnpm build-js-code --script sync_customer`(先 `tsc` 再打包到 `dist/js-code-nodes/<code>/index.cjs`)。CLI validate/create/publish 时会上传快照、用 `{ bucketName, objectName, sha256 }` 替换 `sourceFile.localPath`。
|
|
241
|
+
|
|
242
|
+
## 7. Role — `src/resources/roles/<code>.json`
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"code": "sales",
|
|
247
|
+
"name": "销售"
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## 8. Page Permission Group — `src/resources/permissions/page-groups/<code>.json`
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"code": "sales_pages",
|
|
256
|
+
"name": "销售页面",
|
|
257
|
+
"roles": ["sales"],
|
|
258
|
+
"formCodes": ["customer", "orders"],
|
|
259
|
+
"pageCodes": ["dashboard"]
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`formCodes` / `pageCodes` / `menuCodes` 留空表示对匹配角色全部可见。
|
|
264
|
+
|
|
265
|
+
## 9. Form Permission Group — `src/resources/permissions/form-groups/<formCode>/<groupCode>.json`
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"code": "sales_view",
|
|
270
|
+
"name": "销售查看",
|
|
271
|
+
"type": "view",
|
|
272
|
+
"roles": ["sales"],
|
|
273
|
+
"operations": ["view"],
|
|
274
|
+
"dataScope": {
|
|
275
|
+
"type": "expression",
|
|
276
|
+
"match": "all",
|
|
277
|
+
"conditions": [
|
|
278
|
+
{ "field": "ownerScopeKey", "op": "=", "valueRef": "currentUser.id" }
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
"fieldPermissions": {
|
|
282
|
+
"internalNote": "hidden",
|
|
283
|
+
"amount": "readonly"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## 10. Form Settings — `src/resources/settings/forms/<formCode>.json`
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"code": "customer",
|
|
293
|
+
"settings": {
|
|
294
|
+
"submitButtonText": "提交",
|
|
295
|
+
"successMessage": "提交成功"
|
|
296
|
+
},
|
|
297
|
+
"indexes": [
|
|
298
|
+
{ "fields": ["customerCode"], "unique": true },
|
|
299
|
+
{ "fields": ["status", "ownerDept"] }
|
|
300
|
+
],
|
|
301
|
+
"dataManagement": { "enabled": true, "default": "list" },
|
|
302
|
+
"publicAccess": { "enabled": false }
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## 11. Menu — `src/resources/menus/<code>.json`
|
|
307
|
+
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"code": "main",
|
|
311
|
+
"name": "主菜单",
|
|
312
|
+
"type": "nav",
|
|
313
|
+
"children": [
|
|
314
|
+
{ "code": "customer-entry", "name": "客户信息", "type": "receipt", "formCode": "customer" },
|
|
315
|
+
{ "code": "orders-entry", "name": "订单", "type": "receipt", "formCode": "orders" },
|
|
316
|
+
{ "code": "dashboard-entry","name": "驾驶舱", "type": "page", "pageCode": "dashboard" }
|
|
317
|
+
]
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## 选型决策树
|
|
322
|
+
|
|
323
|
+
```text
|
|
324
|
+
需要展示数据?
|
|
325
|
+
├─ 单表 CRUD → 表单页 + DataManagementList(不要 data view)
|
|
326
|
+
├─ 多表只读联表 → src/resources/data-views/
|
|
327
|
+
├─ 表单字段下拉 → SelectField + optionSource.type: "linkedForm"(不要 data view)
|
|
328
|
+
└─ 大屏 / 报表 → 原生报表 → ECharts page
|
|
329
|
+
|
|
330
|
+
需要后端逻辑?
|
|
331
|
+
├─ 真有审批 → workflow(src/workflows/<code>/workflow.ts)
|
|
332
|
+
├─ 状态流转 → 表单 status 字段 + 状态机 + automation
|
|
333
|
+
├─ 提交/字段触发 → automation(trigger_v2 + src/automations/<code>/index.ts)
|
|
334
|
+
├─ 定时任务 → automation(mode: "scheduled")
|
|
335
|
+
└─ 复杂后端逻辑 → JS_CODE V2 trusted_node(src/js-code-nodes/<code>/index.ts)
|
|
336
|
+
|
|
337
|
+
需要外部数据?
|
|
338
|
+
├─ 第三方 HTTP → src/resources/connectors/ + sdk.connector.call
|
|
339
|
+
└─ 钉钉 / 飞书等 → 同上,平台后端配置 OAuth/AK,前端只引用 connector code
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## 常见错误
|
|
343
|
+
|
|
344
|
+
- ❌ 把 `formUuid` / `pageId` 等平台 ID 写进 manifest。**用 code,CLI 自动解析。**
|
|
345
|
+
- ❌ 把 API key、token、密码写进 manifest。**用占位符,平台后台填真实值。**
|
|
346
|
+
- ❌ 同时在 manifest 与平台后台编辑同一个资源(漂移源)。**统一以 manifest 为单一来源**,需要看平台版本就 `resource pull`。
|
|
347
|
+
- ❌ 用 data view 代替 `linkedForm` 下拉、单表 CRUD 或写回。**data view 是只读 + 延迟刷新。**
|
|
348
|
+
- ❌ 在 page 源码里 hardcode `/api/notification-config/*` 或 `/connectors/actions/invoke`。**用 `sdk.notification` / `sdk.connector`。**
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-app
|
|
3
|
-
description: Manage OpenXiangda low-code apps
|
|
3
|
+
description: Manage OpenXiangda low-code apps and workspaces — create / scaffold / bind / inspect / publish apps, manage menus / nav / 导航 / 菜单, app snapshots, and the profile-isolated `.openxiangda/state.json` resource map. Trigger on 创建应用 / 新建 app / scaffold app / 初始化工作区 / workspace init / workspace bind / appType / APP_XXX / app snapshot / 应用快照 / 菜单 / menu / nav, or when the user starts work in an empty folder that should become a sy-lowcode-app-workspace.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda App
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User wants to **create / scaffold a new app** or initialize a `sy-lowcode-app-workspace`.
|
|
11
|
+
- User wants to **bind** the workspace to an existing platform app (`APP_XXX`) for one profile.
|
|
12
|
+
- User asks about **menus / navigation / app snapshot / appType / .openxiangda/state.json shape**.
|
|
13
|
+
- Before scaffolding a real business app: read the architecture-pattern decision via `references/best-practices.md`.
|
|
14
|
+
|
|
15
|
+
## Decision card — new app vs. bind existing
|
|
16
|
+
|
|
17
|
+
| Situation | Action |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Empty folder, no `.openxiangda/state.json`, user did NOT mention an `appType` | `openxiangda workspace init <dir> --profile <name> --app-name "..."` (creates a NEW app) |
|
|
20
|
+
| User explicitly provides `APP_XXX` or asks to reuse an existing app | `workspace init <dir> --profile <name> --app-type APP_XXX` |
|
|
21
|
+
| Existing workspace, no binding for the target profile | `openxiangda workspace bind --profile <name> --app-type APP_XXX` |
|
|
22
|
+
| Workspace already bound for the target profile | use it; never re-bind silently |
|
|
23
|
+
|
|
24
|
+
**Never** search the platform for similar app names to "reuse" — local `.openxiangda/state.json` is authoritative.
|
|
9
25
|
|
|
10
26
|
## Required Context
|
|
11
27
|
|
|
@@ -1,10 +1,46 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-core
|
|
3
|
-
description: Core OpenXiangda CLI workflow
|
|
3
|
+
description: Core OpenXiangda CLI workflow — normal-user token login, platform profiles (dev / prod / staging), workspace init / bind / publish, multi-platform release, environment / version / token diagnostics. Trigger on 发布 / 上线 / 部署 / publish / deploy / ship / release, 登录 / login / 切换平台 / switch profile / token / whoami / auth, `openxiangda env` / `auth status` / `update check`, `OPENXIANGDA_PROFILE / BASE_URL / ACCESS_TOKEN / APP_TYPE`, or any release operation that must inject the profile token into a sy-lowcode-app-workspace publish.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda Core
|
|
7
7
|
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User wants to **publish / deploy / release / 发布 / 上线 / 部署** anything from a `sy-lowcode-app-workspace`.
|
|
11
|
+
- User asks about **login / profile / token / whoami / 切平台 / 多环境**.
|
|
12
|
+
- User runs into **CLI version drift, skill mismatch, missing OSS env, or `OPENXIANGDA_*` env questions**.
|
|
13
|
+
- Any other skill needs to **resolve the active profile / appType / baseUrl** before write operations.
|
|
14
|
+
|
|
15
|
+
## Default publish recipe (read this before any release)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1. preflight
|
|
19
|
+
openxiangda env --profile <name>
|
|
20
|
+
openxiangda auth status --profile <name>
|
|
21
|
+
openxiangda update check --json # if updateAvailable: openxiangda update install
|
|
22
|
+
|
|
23
|
+
# 2. preview the change set (NEVER skip --dry-run on routine edits)
|
|
24
|
+
openxiangda workspace publish --profile <name> --changed --dry-run
|
|
25
|
+
|
|
26
|
+
# 3. publish only what changed
|
|
27
|
+
openxiangda workspace publish --profile <name> --changed
|
|
28
|
+
# or targeted:
|
|
29
|
+
openxiangda workspace publish --profile <name> --page <pageCode>
|
|
30
|
+
openxiangda workspace publish --profile <name> --form <formCode>
|
|
31
|
+
openxiangda workspace publish --profile <name> --only pages/dashboard,forms/customer
|
|
32
|
+
|
|
33
|
+
# 4. full publish only when shared/config changes intentionally affect many modules
|
|
34
|
+
openxiangda workspace publish --profile <name>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## DO NOT
|
|
38
|
+
|
|
39
|
+
- ❌ `pnpm publish:all` / `pnpm publish:oss` / `pnpm register` / `lowcode-workspace publish-*` directly. They are workspace internals and miss `OPENXIANGDA_PROFILE / BASE_URL / ACCESS_TOKEN / APP_TYPE` injection.
|
|
40
|
+
- ❌ Reuse a `formUuid` / `pageId` / `workflowId` / `automationId` from `dev` for `prod`. Each profile has its own resource map under `.openxiangda/state.json`.
|
|
41
|
+
- ❌ Run a full `workspace publish` reflexively after editing one file.
|
|
42
|
+
- ❌ Ask for AK/SK or store tokens in project files.
|
|
43
|
+
|
|
8
44
|
## Login
|
|
9
45
|
|
|
10
46
|
Use ordinary platform login:
|
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-form
|
|
3
|
-
description: Create
|
|
3
|
+
description: Create / edit / publish OpenXiangda normal forms and workflow forms in `sy-lowcode-app-workspace` — schema, fields, options, validation rules, layout, linkedForm select sources, hidden permission scope keys, top-level FormEffect, workflow form bundles, single-form publish. Trigger on 创建表单 / 新建表单 / 表单字段 / 修改 schema / form field / placeholder / options / SelectField / linkedForm / FormEffect / workflow form / 审批表单页 / form schema / formCode / src/forms, or any change to `src/forms/<code>/{schema.ts,page.tsx}`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda Form
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User wants to **create / edit a form (`src/forms/<code>/`)**, change fields, options, layout, validation, or top-level FormEffect.
|
|
11
|
+
- User wants a **workflow form page** (used together with `openxiangda-workflow-automation`).
|
|
12
|
+
- User wants to **publish only a form** (`workspace publish --form <code>`) or pull / inspect an existing form schema.
|
|
13
|
+
- User asks how form values are persisted (option `{label, value}`, attachment shape, member fields, etc.).
|
|
14
|
+
|
|
15
|
+
## Quick recipe
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1. preflight
|
|
19
|
+
openxiangda env --profile <name>
|
|
20
|
+
openxiangda form list --profile <name>
|
|
21
|
+
|
|
22
|
+
# 2. edit source
|
|
23
|
+
# src/forms/<formCode>/schema.ts — fields, options, rules, top-level FormEffect[]
|
|
24
|
+
# src/forms/<formCode>/page.tsx — presentation only
|
|
25
|
+
|
|
26
|
+
# 3. preview + publish single form
|
|
27
|
+
openxiangda workspace publish --profile <name> --form <formCode> --dry-run
|
|
28
|
+
openxiangda workspace publish --profile <name> --form <formCode>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## DO / DO NOT
|
|
32
|
+
|
|
33
|
+
- ✅ `defineFormSchema` from `openxiangda` and default-export it.
|
|
34
|
+
- ✅ Every visible field has a concise user-facing `placeholder`. Use `tips` only for special constraints.
|
|
35
|
+
- ✅ Use `SelectField` / `RadioField` for enums; for cross-form sources use `SelectField` with `optionSource.type: "linkedForm"` (and `remoteSearch: true` + `searchFieldId` when source is large).
|
|
36
|
+
- ✅ Permission scope keys / sync keys / derived fields stay in schema with `behavior: "HIDDEN"`, derived from visible select/person/department fields via `valueSync`.
|
|
37
|
+
- ✅ Always provide `options` for option components (Select / MultiSelect / Radio / Checkbox / CascadeSelect).
|
|
38
|
+
- ❌ `AssociationFormField` for new form work (use `linkedForm` SelectField).
|
|
39
|
+
- ❌ Top-level `schema.rules` as validation array. Top-level `rules` is `FormEffect[]` only (`when` / `then`).
|
|
40
|
+
- ❌ Extra fields for system metadata (creator / updater / created/updated time / depts) — platform creates them automatically.
|
|
41
|
+
- ❌ Developer notes / implementation comments inside labels / placeholders / tips / section titles / empty states.
|
|
42
|
+
- ❌ `openxiangda form create` as page generation; it is a low-level repair command.
|
|
43
|
+
- ❌ Copy `formUuid` from dev to prod — each profile has its own `formUuid` under `.openxiangda/state.json`.
|
|
9
44
|
|
|
10
45
|
## Required Workspace Flow
|
|
11
46
|
|
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-inspect
|
|
3
|
-
description: Read-only OpenXiangda diagnosis
|
|
3
|
+
description: **Read-only** OpenXiangda diagnosis — app snapshots (应用快照), forms, workflows, automations, automation executions / logs, permissions, profile drift, version mismatch, missing OSS env, broken bundle URLs, page render failures (`options is undefined`, missing styles, raw value labels). Trigger on 诊断 / 排查 / 看一下 / 对比 / diagnose / inspect / debug / why / 为什么 / 报错 / error / failure / 跳越 / drift / snapshot / 快照, or any read-only verification before / after a change. Switch to the relevant write skill (`openxiangda-form` / `-page` / `-workflow-automation` / `-permission-settings`) for remediation.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda Inspect
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User wants to **see what's on the platform** for an app / form / page / workflow / automation / permission group.
|
|
11
|
+
- User reports a **bug, error, drift, or unexpected platform state** and you need evidence before changing anything.
|
|
12
|
+
- You need to **compare** local `.openxiangda/state.json` with the live platform.
|
|
13
|
+
- You need **automation execution traces / logs** to understand why a trigger didn't fire or a node failed.
|
|
14
|
+
|
|
15
|
+
## Decision card
|
|
16
|
+
|
|
17
|
+
| Scenario | Command |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Before any non-trivial edit to an existing app | `openxiangda app snapshot APP_XXX --profile <name> --json` |
|
|
20
|
+
| Form schema looks wrong on platform | `openxiangda inspect form <code> --profile <name> --json` |
|
|
21
|
+
| Workflow / automation doesn't run as expected | `openxiangda inspect workflow <code> --profile <name> --json` / `automation executions <code>` / `automation logs` / `automation diagnose <code>` |
|
|
22
|
+
| Permission visibility doesn't match expectation | `openxiangda inspect permissions <formCode> --profile <name> --json` |
|
|
23
|
+
| Local state out of sync with platform | `openxiangda form list / page list / workflow list / automation list --profile <name>` |
|
|
24
|
+
|
|
25
|
+
## Rules
|
|
26
|
+
|
|
27
|
+
- ✅ **Read-only.** This skill never writes / publishes / mutates.
|
|
28
|
+
- ✅ Use **logical local codes** first; pass live IDs only when the code is missing from `.openxiangda/state.json`, and only for the current profile.
|
|
29
|
+
- ✅ Cross-check unexpected values against `references/platform-data-model.md` (option `{label, value}`, attachment shape, member fields, JSONB) before claiming a bug.
|
|
30
|
+
- ✅ Cross-check render / runtime issues against `references/troubleshooting.md` before patching symptoms.
|
|
31
|
+
- ❌ Treat IDs from another profile as evidence — always confirm with `openxiangda env --profile <name>` first.
|
|
32
|
+
- ❌ Mutate from this skill. For remediation, hand off to the relevant write skill.
|
|
9
33
|
|
|
10
34
|
## Commands
|
|
11
35
|
|
|
@@ -1,11 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-page
|
|
3
|
-
description: Build
|
|
3
|
+
description: Build / edit / publish OpenXiangda custom code pages in `sy-lowcode-app-workspace/src/pages/<pageCode>/` using React + Ant Design + `openxiangda/runtime`. Covers app-shell portals, dashboards, workbenches, data-management lists, mobile portals, page-level connector calls, and single-page publish. Trigger on 创建页面 / 新建页面 / 修改页面 / portal / dashboard / 看板 / 驾驶舱 / 工作台 / 列表页 / mobile portal / app-shell / page.config.ts / pageCode / src/pages, JSX / React / Ant Design page work in this workspace, or any change to `src/pages/<code>/`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda Page
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User wants to **create / edit a custom code page** under `src/pages/<pageCode>/` (portal, dashboard, list/detail, workbench, mobile portal, etc.).
|
|
11
|
+
- User wants to **publish only a page** (`workspace publish --page <code>`) or rebuild a single page bundle.
|
|
12
|
+
- User asks about page SDK (`openxiangda/runtime`), `page.config.ts`, app-shell entry mode, namespace/style isolation, ECharts, drag-drop, antd icons, or named imports from `@ant-design/icons`.
|
|
13
|
+
- User asks about **portal / admin console / mobile portal entry** — these must be app-shell code pages.
|
|
14
|
+
|
|
15
|
+
## Quick recipe
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1. preflight
|
|
19
|
+
openxiangda env --profile <name>
|
|
20
|
+
openxiangda page list --profile <name>
|
|
21
|
+
|
|
22
|
+
# 2. edit source under src/pages/<pageCode>/
|
|
23
|
+
# page.config.ts (entry mode, route, navigation), domain/, shared/services/, shared/hooks/, components/, styles.css
|
|
24
|
+
|
|
25
|
+
# 3. preview + publish single page
|
|
26
|
+
openxiangda workspace publish --profile <name> --page <pageCode> --dry-run
|
|
27
|
+
openxiangda workspace publish --profile <name> --page <pageCode>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## DO / DO NOT
|
|
31
|
+
|
|
32
|
+
- ✅ Formal user-facing entries (admin console / PC portal / mobile portal) MUST be app-shell pages: `entry: { mode: "app-shell", hidePlatformNav: true, defaultRoute: "<home>" }` in `page.config.ts`.
|
|
33
|
+
- ✅ Default to **native Tailwind utilities** for new pages (`bg-white`, `border-slate-200`, `grid-cols-[240px_1fr]`, ...) and `cssIsolation: "none"`. Keep namespace/shadow only for explicit legacy compatibility.
|
|
34
|
+
- ✅ Split complex pages into `domain/`, `shared/services/`, `shared/hooks/`, `components/`, route/config files, `styles.css` (see `references/best-practices.md` and `references/architecture-patterns.md`).
|
|
35
|
+
- ✅ List/detail/CRUD pages: follow `DataManagementList` pattern from `references/architecture-patterns.md`. Pagination + structured `filterGroup` + `OR`. Never fetch huge `pageSize` and filter in browser.
|
|
36
|
+
- ✅ For external APIs use `src/resources/connectors/<code>.json` + `sdk.connector.invoke()`; for joined read-only queries use `src/resources/data-views/<code>.json`.
|
|
37
|
+
- ❌ Single-file giant pages. Split per `references/best-practices.md`.
|
|
38
|
+
- ❌ Hardcoded `/view/...&isRenderNav=false` URLs scattered through page code; use the runtime navigation helper.
|
|
39
|
+
- ❌ shadcn token classes like `bg-card` / `text-muted-foreground` / `text-foreground` unless explicitly configured.
|
|
40
|
+
- ❌ Embed a single `FormProvider` field component temporarily; navigate to a full standard form page or render a complete `StandardFormPage` instead.
|
|
41
|
+
- ❌ Reuse one form UI for both PC and mobile without verifying overlay / picker / bottom-sheet behavior on both viewports.
|
|
42
|
+
- ❌ Hardcode notification or platform API URLs; use `openxiangda/runtime` and `src/resources/notifications/` declarations.
|
|
9
43
|
|
|
10
44
|
## CLI Flow
|
|
11
45
|
|
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-permission-settings
|
|
3
|
-
description: Manage OpenXiangda app roles, page permission groups, form permission groups, and
|
|
3
|
+
description: Manage OpenXiangda app **roles** (角色), **page permission groups** (页面权限组 / 菜单可见), **form permission groups** (表单权限组 / 提交 / 查看 / 字段权限 / 数据范围 / 数据隔离), and **form settings** (表单设置 / 索引 / 数据管理页 / 公开访问 / public access / 分享) with profile-isolated IDs and ordinary user token permissions. Trigger on 角色 / role / 权限 / permission / 数据范围 / data scope / 字段权限 / field permission / 菜单可见 / menu visibility / 公开访问 / public access / 分享 / share, or any work touching `permission ...` / `settings ...` CLI commands or `src/resources/{roles,pagePermissionGroups,formPermissionGroups,formSettings}/`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda Permission And Settings
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User wants to **define / modify roles** for the app.
|
|
11
|
+
- User wants to **gate menu / page visibility** (page permission groups).
|
|
12
|
+
- User wants to **gate form submit / view / edit / data scope / field permissions** (form permission groups).
|
|
13
|
+
- User wants to **publish a form publicly** or change form runtime settings, indexes, data-management page config.
|
|
14
|
+
- User asks about **dynamic role governance** (role maintenance form synced to platform via automation).
|
|
15
|
+
|
|
16
|
+
## DO / DO NOT
|
|
17
|
+
|
|
18
|
+
- ✅ Use logical role / group codes locally; live IDs go under the active profile in `.openxiangda/state.json`.
|
|
19
|
+
- ✅ For dynamic multi-role apps, build a role maintenance form + automation/JS_CODE sync, not hardcoded role logic in page code.
|
|
20
|
+
- ✅ For permission scope keys, derive hidden scalars (`collegeScopeKey`, `classScopeKey`, `ownerDeptScopeKey`, `ownerUserScopeKey`, `roleCode`) via `valueSync` from visible select/person/department fields.
|
|
21
|
+
- ✅ Use page permission groups for entry visibility, form permission groups for real data isolation with condition-based data permissions.
|
|
22
|
+
- ❌ Expose raw ID text fields to users for permission scopes.
|
|
23
|
+
- ❌ Store platform-specific public-access IDs locally; CLI resolves by `appType + formUuid` per profile.
|
|
24
|
+
- ❌ Reuse role / permission-group IDs across profiles.
|
|
25
|
+
- ❌ Use AK/SK or legacy `/dingtalk-api/v1.0` — the logged-in user must have the matching app permission.
|
|
9
26
|
|
|
10
27
|
## Required Context
|
|
11
28
|
|
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openxiangda-workflow-automation
|
|
3
|
-
description: Build
|
|
3
|
+
description: Build / validate / publish / enable / inspect OpenXiangda **workflows** (审批流程 / approval / approve / reject / transfer / withdraw, v3 graph, JS_CODE trusted_node) and **automations** (自动化 / 集成 / 定时任务 / cron / form data submit/update/delete events, form field change, workflow task / process events, message notifications). Includes architecture boundary between workflow and normal status-machine forms, code-first workflows (`src/workflows/<code>/workflow.ts`) and code-first automations (`src/automations/<code>/index.ts`). Trigger on 审批 / 流程 / workflow / approval / process / 节点 / 并行分支 / 条件分支 / 代办 / 转交 / 撤回 / 驳回 / 自动化 / automation / cron / 定时 / 提交后 / 字段变更 / JS_CODE / trusted_node / src/js-code-nodes.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OpenXiangda Workflow And Automation
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## When to use this skill
|
|
9
|
+
|
|
10
|
+
- User asks for **approval workflows / 审批 / 流程 / approve / reject / transfer / withdraw / process records / approval-node side effects**.
|
|
11
|
+
- User asks for **automation / 自动化 / cron / 定时 / form-data-submitted/updated/deleted / field-changed / workflow-task-approved / message notification triggers**.
|
|
12
|
+
- User asks for **JS_CODE backend script** (cross-form query, batch update, terminate process, external HTTP, complex orchestration that frontend can't handle).
|
|
13
|
+
- User wants **code-first workflow / automation** (TypeScript source under `src/workflows/` or `src/automations/`).
|
|
14
|
+
|
|
15
|
+
## Boundary — workflow vs. status field
|
|
16
|
+
|
|
17
|
+
**Most business lifecycle flows are NOT workflows.** For ordinary `pending → processing → resolved → closed`, use a normal form + `status` field + responsibility fields + action-log form + state machine + automation/JS_CODE.
|
|
18
|
+
|
|
19
|
+
Create a workflow only when the scenario has **real approval semantics**: approvers, approval tasks, agree/reject actions, opinions, node-level field permissions, process records, approval-node side effects.
|
|
20
|
+
|
|
21
|
+
## DO / DO NOT
|
|
22
|
+
|
|
23
|
+
- ✅ New AI-authored automations: prefer **code-first** `automation_code_ts` (`src/automations/<code>/index.ts` + `definition.code.json` + `preview.json`).
|
|
24
|
+
- ✅ New AI-authored workflows that don't need canvas editing: prefer **code-first** `src/workflows/<code>/workflow.ts` using `openxiangda/workflow`.
|
|
25
|
+
- ✅ JS_CODE V2 trusted_node: source in TypeScript under `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.ts`. Run `pnpm build-js-code --script <code>` (validates with `tsc` first).
|
|
26
|
+
- ✅ Use `trigger_v2` for new automation triggers; CLI fills root `appType` / `formUuid` from active profile when `--form-code` is provided.
|
|
27
|
+
- ✅ Use logical `workflowCode` / `automationCode` locally; live IDs are profile-isolated under `.openxiangda/state.json`.
|
|
28
|
+
- ✅ `ctx.logger.debug/info/warn/error(message, data?)` at every important step — inspect via `automation executions` / `automation logs` / `automation diagnose`.
|
|
29
|
+
- ❌ JS_CODE for simple UI interactions, ordinary form validation, or display-only logic — those belong to a normal React code page.
|
|
30
|
+
- ❌ Workflow definitions for non-approval status changes — use a status field instead.
|
|
31
|
+
- ❌ Copy `workflowId` / `automationId` across profiles. Always create/bind separately for each profile.
|
|
32
|
+
- ❌ Inline large JS code blobs in v3 JSON for new work — use trusted_node TypeScript snapshots.
|
|
9
33
|
|
|
10
34
|
## Architecture Boundary
|
|
11
35
|
|