Compare commits

..

3 Commits

Author SHA1 Message Date
1e2f94dd10 docs: Excel import template dropdowns from column metadata
All checks were successful
技能自动化发布 / release (push) Successful in 24s
2026-10-12 21:09:49 +08:00
72817f6cdd Release v1.0.123: document cron empty-selection branch for selectionMode optional
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-10-07 14:33:01 +08:00
6644dedd0e Release v1.0.122: document Action enumNames and column-bound static enum labels
All checks were successful
技能自动化发布 / release (push) Successful in 9s
2026-10-01 17:26:19 +08:00
13 changed files with 174 additions and 26 deletions

View File

@@ -9,6 +9,23 @@
- 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节
- 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段
## 1.0.124
- 沉淀宿主能力:Excel 导入模板按列元数据自动加下拉(有可选集合的列展示 label;CSV 无下拉);技能只需声明 `_jiangchang_columns` 选项即可受益
- 更新 `references/SCHEMA.md`「宿主负责」与 `options_json` 说明
## 1.0.123
- 沉淀 `selectionMode: optional` 在**定时任务等无表勾选入口**的宿主约定:配置页按无勾选分支,隐藏空「编号列表」、只保留数量字段;勿为 cron 再拆 Action
- 更新 ACTIONS / CHECKLIST A4-9 / RUNTIME / DEVELOPMENT 验收表;门禁用例覆盖关键表述
## 1.0.122
- 沉淀 Action **静态枚举中文 label**:`enum` + **`enumNames`**,或绑列复用列 `options_json` 数组
- 约定宿主优先序:**绑列 options → enumNames → 纯 enum**;固定小枚举不要造假 Lookup
- 更新 Schema / ACTIONS / SCHEMA / CHECKLIST A4-13;新增 `enum-names-action.example.json`
## 1.0.121
- 沉淀 Lookup **分页勾选小表**:`display_type: lookup` + `presentation: "paged_table"` + 可选 `page_size`(仍是 Lookup,不要新造控件类型)

View File

@@ -1,7 +1,7 @@
---
name: 技能开发模板(通用业务版)
description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。"
version: 1.0.121
version: 1.0.124
author: 深圳匠厂科技有限公司
metadata:
openclaw:
@@ -38,7 +38,7 @@ allowed-tools:
- **数据管理**:既是 **UI 执行面**(点按钮走与对话相同的闭环),也是数据与过程可见;不是「只读库」。
- **`placements`**:只决定 Action **出现在哪里**(toolbar / row / batch / cron / agent / skill-detail)。其中 `row` 表示**行级入口**(宿主可呈现为操作列、行右键、行内「⋯」等;技能配什么就显示什么,无独立菜单 DSL)。数据管理技能按钮顺序见 `actions` **数组相对顺序**(详见 `references/ACTIONS.md`),无独立 sortOrder。
- **`bind.tables`**:只决定数据管理出现在哪些表;含 `toolbar` 时**必须**显式非空绑定。
- **`bind.selectionMode`(可选)**:表勾选如何驱动 Action(`required` / `none` / `optional`);省略由宿主推断。同一能力勿拆两个同义顶栏按钮,见 `references/ACTIONS.md`。
- **`bind.selectionMode`(可选)**:表勾选如何驱动 Action(`required` / `none` / `optional`);省略由宿主推断。同一能力勿拆两个同义顶栏按钮;定时任务配置页按无勾选分支隐藏 `$selection.ids`,见 `references/ACTIONS.md`。
- **`bind.visibleWhen`(可选)**:`row` 菜单/按钮按当前行列值显隐(如仅已采用可入队);省略则始终显示。≠ 表单字段 `visibleWhen`,≠ Policy L3。见 `references/ACTIONS.md`「行菜单显隐」。
- **用户可见文案**:数据管理弹窗 / 任务中心文案须全中文产品用语;勿把 `pickCount`、`async`、`pending`、CLI 子命令写进弹窗(见 `references/ACTIONS.md`「用户可见文案」)。
- **`executionProfile`**:只决定执行方式——`sync` 当场返回结果,`async` 进**任务中心**。与 placements / 入口**无关**。心智上多数为 sync,仅长任务 / RPA 标 async;宿主省略该字段时按 sync。每个 Action **仍必须**显式写 `sync` 或 `async`。

View File

@@ -13,5 +13,5 @@
- `visible-when-action.example.json`:Action 参数字段条件显隐 `visibleWhen` 形状参考(互斥模式联动;见 `references/ACTIONS.md`「字段条件显隐」;≠ `bind.visibleWhen`,≠ Policy L3)。
- `bind-visible-when-row.action.example.json`:行菜单显隐 `bind.visibleWhen` 形状参考(按当前行状态显示/隐藏行按钮;见 `references/ACTIONS.md`「行菜单显隐」)。
- `selection-label-column.action.example.json`:选择摘要 `bind.labelColumn` 形状参考(见 `references/ACTIONS.md`「选择摘要」)。
- `selection-mode-optional.action.example.json`:`bind.selectionMode: "optional"` 智能勾选/按数量合并形状参考;用户可见文案为口语中文(见 `references/ACTIONS.md`「勾选驱动模式」「用户可见文案」)。
- `selection-mode-optional.action.example.json`:`bind.selectionMode: "optional"` 智能勾选/按数量合并形状参考(含 `cron`:配置页按无勾选分支,只见数量字段);用户可见文案为口语中文(见 `references/ACTIONS.md`「勾选驱动模式」「用户可见文案」)。
- `replaces-create.action.example.json` / `replaces-update.action.example.json` / `replaces-delete.action.example.json` / `replaces-import.action.example.json`:数据管理默认按钮接管(`replaces`)形状参考;**import 时 UI 仍用宿主「导入数据」面板**,确认后调技能写库(见 `references/ACTIONS.md`「`replaces`」)。

View File

@@ -0,0 +1,51 @@
{
"_comment": "形状参考:Action 静态枚举用 enum + enumNames 显示中文;提交仍是 enum value。有对应表列时优先 column 绑列复用 options_json。完整契约见 references/ACTIONS.md「静态枚举 label」。",
"schemaVersion": 1,
"skill": "your-skill-slug",
"actions": [
{
"id": "create-ticket",
"label": "新建工单(示例)",
"description": "演示 enumNames:界面显示中文,CLI 仍收到英文枚举值。",
"placements": ["toolbar", "agent"],
"executionProfile": "sync",
"interaction": "form",
"bind": {
"tables": ["tickets"]
},
"entrypoint": {
"type": "cli",
"command": "ticket-create",
"args": [
"--category", "{{category}}",
"--priority", "{{priority}}",
"--title", "{{title}}"
]
},
"inputSchema": {
"type": "object",
"required": ["title", "category"],
"properties": {
"title": {
"type": "string",
"title": "标题"
},
"category": {
"type": "string",
"title": "类型",
"column": "category",
"enum": ["incident", "request", "consult", "other"],
"enumNames": ["故障", "需求", "咨询", "其他"]
},
"priority": {
"type": "string",
"title": "优先级",
"enum": ["low", "medium", "high", "urgent"],
"enumNames": ["低", "中", "高", "紧急"],
"description": "无对应列时仅靠 enumNames 展示中文"
}
}
}
}
]
}

View File

@@ -147,7 +147,13 @@
"default": {},
"enum": {
"type": "array",
"minItems": 1
"minItems": 1,
"description": "静态枚举取值(提交/存库用)。展示中文时配 enumNames,或绑列复用 options_json;勿用 Lookup 冒充固定小枚举。"
},
"enumNames": {
"type": "array",
"minItems": 1,
"description": "可选。与 enum 一一对应的展示文案(JSON Schema / OpenAPI 风格)。缺项或空串时宿主回退为对应 enum 原文。有对应表列时优先绑列复用 options_json(见 ACTIONS.md「静态枚举 label」)。"
},
"sensitive": { "type": "boolean" },
"readOnly": {
@@ -162,7 +168,7 @@
"type": "string",
"minLength": 1,
"pattern": "^[a-z][a-z0-9_]*$",
"description": "可选。绑定业务表物理列名;Action 弹窗(toolbar/batch)与 replaces create/update 抽屉均可复用该列的中文名与 lookup 下拉"
"description": "可选。绑定业务表物理列名;Action 弹窗(toolbar/batch)与 replaces create/update 抽屉可复用该列的中文名与 options(静态枚举 options_json 数组,或已解析的 lookup)。"
},
"display_type": {
"type": "string",

View File

@@ -111,10 +111,11 @@ checklist_version: 1.0
- [ ] A4-6 **P0** 若 Action 需引用业务行(话术/平台/账号等):参数为 Lookup 下拉(**不是**手填内部编号);同库用 `local_sql`(内联或绑列),跨技能用 **`skill_cli`**(勿在本库造镜像缓存表);可选「自动」可留空提交(见 `references/ACTIONS.md`)
- [ ] A4-7 **P1** 若 Action 有互斥采集/操作模式(如「按关键词 / 按主页」):用 `inputSchema` 字段级 **`visibleWhen`** 联动显隐,勿只靠 `description` 灰字说明「仅某某时填写」(见 `references/ACTIONS.md`;勿与 **`bind.visibleWhen`** 行菜单、Policy L3 混淆)
- [ ] A4-8 **P1** 行内/勾选打开的 `form`:有「已选择」时参数区不应再重复映射主键(`inputMapping` + `readOnly`);需要强制露出时用 `revealInForm`,**禁止**用表单 `visibleWhen` 藏主键(会不提交)
- [ ] A4-9 **P1** 若同一能力既支持「勾选处理」又支持「按数量从队列领取」:用一个 Action + `bind.selectionMode: "optional"`(勿拆两个同义顶栏按钮);无勾选可点、有勾选显示「已选择」、空选数量字段用 `pickCount` 等约定名(见 `references/ACTIONS.md`)
- [ ] A4-9 **P1** 若同一能力既支持「勾选处理」又支持「按数量从队列领取」:用一个 Action + `bind.selectionMode: "optional"`(勿拆两个同义顶栏 / cron 按钮);无勾选可点、有勾选显示「已选择」、空选数量字段用 `pickCount` 等约定名;**定时任务配置页**只应出现数量字段、不应出现空的「编号列表」(见 `references/ACTIONS.md`)
- [ ] A4-10 **P0** 数据管理弹窗与任务失败文案:全中文产品用语;禁止在 `description` / `confirmation.message` / 参数 `description` / 用户向 `message` 写英文字段名、CLI 子命令、`async`/`pending`/`status=` 等(Agent 路由放 `SKILL.md`;见 `references/ACTIONS.md`「用户可见文案」)
- [ ] A4-11 **P1** 若行操作应按业务状态显隐(如仅待确认可「采用」、仅已采用可「加入待写」):用 **`bind.visibleWhen`**(对当前行列值求值;存库原始值如 `approved`);勿指望 Policy L3;CLI 侧仍须校验状态(见 `references/ACTIONS.md`「行菜单显隐」)
- [ ] A4-12 **P1** 若要在表单里翻页勾选一批业务行(文章、平台等):用 Lookup **`presentation: "paged_table"`**(仍是 `display_type: lookup`,勿新造类型);`skill_cli` 的 stdout 为一行 `{"items","total"}`,0 条也成功退出;该列表命令不要在入口加载整包 platform-kit 或 Playwright(见 `references/ACTIONS.md`「分页勾选小表」)
- [ ] A4-13 **P1** 若 Action 有固定小枚举(状态/船司/优先级等)需中文展示:用 `enum` + **`enumNames`**,或绑列复用列 `options_json` 数组;宿主优先序为绑列 options → enumNames → 纯 enum;**禁止**为中文展示造假 Lookup(见 `references/ACTIONS.md`「静态枚举 label」)
---
## 5. 账号与浏览器会话(网页 RPA 适用;其他形态标 N/A 或改测等价项)

View File

@@ -928,7 +928,7 @@ uses: client-jiangchang/jiangchang-platform-kit/.github/workflows/reusable-relea
| **数据管理 · HTML 报告** | 壳子页放 `assets/html/pages/*.html`;快照写出 `html/*.html` 并提供 `render-html` | 壳子装完即现、右键无「重新生成」;快照可重新生成;页面 `jiangchang.call` 能拿到 JSON |
| **数据管理 · 行级** | `placements` 含 `row`(建议 `bind.tables` + `bind.inputMapping` 预填主键) | 操作列和/或行右键(及可选「⋯」)出现本技能行级 Action(需有主键列);点按后入参/行为与壳无关、均正确 |
| **数据管理 · 批量** | `placements` 含 `batch` | 勾选行后批量按钮可用;无勾选时禁用;批量行为正确 |
| **定时任务** | `placements` 含 `cron`(创建时选「技能直调」) | 能选到本技能 Action、保存并触发;到点或「立即运行」行为正确 |
| **定时任务** | `placements` 含 `cron`(创建时选「技能直调」) | 能选到本技能 Action、保存并触发;到点或「立即运行」行为正确;`selectionMode: optional` 时参数区只见数量字段、不见空「编号列表」 |
| **任务中心** | 不是 placement;由 `executionProfile: "async"` 决定是否进 Job | 长任务出现进度 / 可取消;来源标签与触发入口一致 |
| **技能市场 → 技能详情** | `placements` 含 `skill-detail`(详情直调) | **必验**安装与四 Tab。详情页「技能直调」按钮随宿主版本上线;**已声明则须在具备该 UI 的宿主上完成按钮自测**(与其它入口同等对待,不要只靠 Agent) |

View File

@@ -21,7 +21,7 @@
1. **宿主管调度,技能管业务** — 不自行实现任务中心 / Job 轮询 / 后台守护进程。
2. **单业务内核、多入口** — 数据管理、定时任务、Agent、技能详情与直接 CLI 复用同一 domain service;禁止按入口复制业务逻辑。
3. **五职责正交** — `placements` / `bind.tables` / `executionProfile` / `entrypoint` / domain service 各管一事(见 ACTIONS.md)。可选第六轴 **policy**(见 `references/POLICY.md`):未启用 = L0 与今日一致。可选 **`hostEffects` / `steps`**(见 ACTIONS.md):数据管理交互前后的 UI/级联编排;省略 = 不额外改 UI(匠厂宿主 ≥2.8.5)。可选 **`hoverHint`**(见 ACTIONS.md):数据管理工具栏悬停;省略 = 不显示,不回退说明或确认黄条。可选 **表单 `visibleWhen`**(见 ACTIONS.md):Action 参数表单字段条件显隐;省略 = 字段始终平铺;**勿与** **`bind.visibleWhen`**(行菜单)或 Policy L3 混淆;**勿**用其藏映射主键。可选 **`pathRoot`**(见 ACTIONS.md):`file`/`directory` 原生选路对话框起始目录(相对技能数据根;省略默认 `{skill_data}/input`)。可选 **`bind.labelColumn`**(见 ACTIONS.md):选择摘要可读标签列;省略 = 宿主常见列名启发。可选 **`bind.selectionMode`**(见 ACTIONS.md):表勾选如何驱动 Action(`required` / `none` / `optional`);省略 = 宿主按 `$selection.ids` / `batch` 推断。可选 **`bind.visibleWhen`**(见 ACTIONS.md「行菜单显隐」):`row` 菜单按当前行列值显隐;省略 = 始终显示。可选 **`revealInForm`**(见 ACTIONS.md):有「已选择」时仍强制显示某 `readOnly` 字段;省略 = 映射只读默认不占 form 参数区(仍提交)。可选 **`cellPresentation`**(见 `references/CELL_PRESENTATION.md`):单元格/整行/整列/区域语义标色;省略 = P0。**用户可见文案**(见 ACTIONS.md「用户可见文案」):弹窗 `description` / 确认黄条 / 参数说明 / 任务失败 `message` 须全中文产品用语;Agent 路由勿塞进弹窗。
3. **五职责正交** — `placements` / `bind.tables` / `executionProfile` / `entrypoint` / domain service 各管一事(见 ACTIONS.md)。可选第六轴 **policy**(见 `references/POLICY.md`):未启用 = L0 与今日一致。可选 **`hostEffects` / `steps`**(见 ACTIONS.md):数据管理交互前后的 UI/级联编排;省略 = 不额外改 UI(匠厂宿主 ≥2.8.5)。可选 **`hoverHint`**(见 ACTIONS.md):数据管理工具栏悬停;省略 = 不显示,不回退说明或确认黄条。可选 **表单 `visibleWhen`**(见 ACTIONS.md):Action 参数表单字段条件显隐;省略 = 字段始终平铺;**勿与** **`bind.visibleWhen`**(行菜单)或 Policy L3 混淆;**勿**用其藏映射主键。可选 **`pathRoot`**(见 ACTIONS.md):`file`/`directory` 原生选路对话框起始目录(相对技能数据根;省略默认 `{skill_data}/input`)。可选 **`bind.labelColumn`**(见 ACTIONS.md):选择摘要可读标签列;省略 = 宿主常见列名启发。可选 **`bind.selectionMode`**(见 ACTIONS.md):表勾选如何驱动 Action(`required` / `none` / `optional`);省略 = 宿主按 `$selection.ids` / `batch` 推断;**定时任务等无表勾选入口按无勾选分支**(隐藏 `$selection.ids`,保留 `pickCount`)。可选 **`bind.visibleWhen`**(见 ACTIONS.md「行菜单显隐」):`row` 菜单按当前行列值显隐;省略 = 始终显示。可选 **`revealInForm`**(见 ACTIONS.md):有「已选择」时仍强制显示某 `readOnly` 字段;省略 = 映射只读默认不占 form 参数区(仍提交)。可选 **`cellPresentation`**(见 `references/CELL_PRESENTATION.md`):单元格/整行/整列/区域语义标色;省略 = P0。**用户可见文案**(见 ACTIONS.md「用户可见文案」):弹窗 `description` / 确认黄条 / 参数说明 / 任务失败 `message` 须全中文产品用语;Agent 路由勿塞进弹窗。
4. **长耗时建议 async** — 开浏览器、RPA、HTTP 大文件下载等建议 `executionProfile: "async"`,进**任务中心**;这是对**方法**的选择,**不**限制可以出现在哪些 placement / 入口。
5. **Agent:短 CLI / 长 Action** — 短查询可用共享 Python bash CLI;长任务 / RPA **禁止** `exec` + `process poll`,必须 `run_skill_action`。
6. **进度走 Journal** — `emit` / `video.add_step` → Run Journal;UI / Skill Run Card / 任务中心展示;**不靠 stdout 流**。

View File

@@ -110,7 +110,7 @@ Action 是否提供、挂哪些 `placements`,由本技能 **入口定位表**
| **bind** | `{ "tables": ["business_table"] }`;可选 `inputMapping`、`columnMapping`、**`labelColumn`**、**`selectionMode`**、**`visibleWhen`**(行内/批量预填、选择摘要标签、勾选驱动模式、**行菜单显隐**,见下节) |
| **policy** | 可选;`enabled` + `entrypoint`(推荐 `policy` CLI);见 POLICY.md。未启用 = L0 |
| **cellPresentation** | 可选;`{ "enabled": true }` 时宿主应加载格子与 grid 呈现;见 [`CELL_PRESENTATION.md`](CELL_PRESENTATION.md)。未启用 = P0 |
| inputSchema | 根 `type: object`;properties 使用 `string` / `number` / `boolean`;支持 `enum`、`default`、`required`、`sensitive`、`readOnly`、可选 **`revealInForm`**;可选 `display_type` / `format`(含 `file` / `directory` 等);可选 **`pathRoot`**(file/directory 起始目录,相对技能数据根);可选 **`visibleWhen`**(字段条件显隐,见专节) |
| inputSchema | 根 `type: object`;properties 使用 `string` / `number` / `boolean`;支持 `enum`、可选 **`enumNames`**、`default`、`required`、`sensitive`、`readOnly`、可选 **`revealInForm`**;可选 `column`(绑列复用 options);可选 `display_type` / `format`(含 `file` / `directory` 等);可选 **`pathRoot`**(file/directory 起始目录,相对技能数据根);可选 **`visibleWhen`**(字段条件显隐,见专节) |
| confirmation | `{ "message": "..." }` — **风险文案**(confirm/form 弹窗黄条;agent 元数据);**不是**「要不要弹窗」的开关 |
| **hoverHint** | 可选字符串。数据管理**工具栏悬停**文案;与 `description` / `confirmation.message` **独立**。省略则不显示悬停,不回退。短名已够懂时不要写。需宿主已支持该字段;当前实现为顶栏技能按钮,不含宿主内置删除/刷新/新增/导入/导出 |
| **visibleWhen** | 可选。写在 **property** 上(非 action 顶层):依赖同表单其它字段值决定是否展示;隐藏字段不提交、不校验 `required`。**勿与** [`POLICY.md`](POLICY.md) L3 行态 `visibleWhen` 混淆;也**勿**用它藏「已选择」已表达的映射主键(见「选择摘要」) |
@@ -197,7 +197,8 @@ Action 是否提供、挂哪些 `placements`,由本技能 **入口定位表**
3. 空选数量字段名约定(宿主按字段名识别,保守列表):`pickCount` / `maxLeads` / `maxCount` / `takeCount` / `pick`。
4. `entrypoint.args` 可同时写 `--ids {{itemIds}}` 与 `--pick {{pickCount}}`;缺值的 `--flag` + 空串由宿主压缩掉,不会留下脏 argv。
5. 有勾选时隐藏数量字段;无勾选时隐藏 `$selection.ids` 映射字段(`$row.*` 行上下文不受影响)。
6. **不要**为同一能力再挂第二个 toolbar 按钮。
6. **定时任务 / 技能详情等无表勾选入口**:宿主须按「无勾选」分支渲染与保存——只展示 `pickCount` 等数量字段,**不**画出空的「编号列表」类 `$selection.ids` 映射只读框;保存的 `actionInput` 也不应再带上空 `itemIds`。不要为 cron 再拆第二个 Action。
7. **不要**为同一能力再挂第二个 toolbar 按钮。
示例:[`assets/examples/selection-mode-optional.action.example.json`](../assets/examples/selection-mode-optional.action.example.json)。
@@ -437,13 +438,14 @@ Action 是否提供、挂哪些 `placements`,由本技能 **入口定位表**
- 点默认「导入」时**固定**打开宿主导入面板;确认后若有 `replaces:import` 则调用该 Action(`interaction` 不决定是否再弹技能表单)。
- `update` / `delete` 可用 `inputMapping`(`$row.$pk`、`$selection.ids`)预填主键。
- `import` 约定:`filePath`(或 `file`)+ 可选 `onError`(`skip`/`abort` 或上例中文枚举);技能自行解析文件与表头。
- 整表 `_jiangchang_tables.readonly=1` 时仍隐藏写按钮(优先于 `replaces`)。
- **列元数据复用(lookup)**:Action 表单(含 toolbar/batch 弹窗与 create/update 抽屉)可将 `inputSchema` 字段对齐业务列,复用中文名与 lookup 下拉:
- 优先让属性名 = 物理列名(如 `platform_key`);
- 或 `bind.columnMapping`:`{ "platform": "platform_key" }`;
- 或字段上写 `"column": "platform_key"`。
- 当前表没有对应列时,用字段内联 `lookup`(见下文「跨表引用:Lookup」)。
- **不要**在 actions.json 里写死会过期的全量平台 `enum`,也**不要**让用户手填内部编号。
- 整表 `_jiangchang_tables.readonly=1` 时仍隐藏宿主默认新增/编辑/导入与直写删除;**若声明了 `replaces: delete`,宿主仍显示「删除」并走技能 CLI**(不直写 SQLite)。
- **列元数据复用**:Action 表单(含 toolbar/batch 弹窗与 create/update 抽屉)可将 `inputSchema` 字段对齐业务列,复用中文名与列上 **options**(静态枚举 `options_json` **数组**,或已解析的 lookup):
- 优先让属性名 = 物理列名(如 `carrier_code` / `platform_key`);
- 或 `bind.columnMapping`:`{ "carrierCode": "carrier_code" }`;
- 或字段上写 `"column": "carrier_code"`(推荐:驼峰属性名时显式写出,避免只靠启发式)。
- 当前表没有对应列、且选项是**固定小枚举**时:用 `enum` + **`enumNames`**(见下文「静态枚举 label」),**不要**为中文展示去造 Lookup。
- 当前表没有对应列、且选项是**跨表/跨技能业务行**时:用字段内联 `lookup`(见下文「跨表引用:Lookup」)。
- **不要**在 actions.json 里写死会过期的全量业务行 `enum`,也**不要**让用户手填内部编号。
## `interaction`(点击交互方式)
@@ -514,7 +516,7 @@ Action 是否提供、挂哪些 `placements`,由本技能 **入口定位表**
**边界:**
- **cron 配置**:仍展示可编辑参数;`confirmation.message` 可作为配置页风险提示(由宿主决定)。
- **cron 配置**:仍展示可编辑参数;`confirmation.message` 可作为配置页风险提示(由宿主决定)。若 Action 为 `selectionMode: "optional"`(或 `none`),配置页按**无表勾选**分支:隐藏 `$selection.ids` 映射字段,只保留数量等可编辑参数(见上文「勾选驱动模式」第 6 点)。
- **cron 触发 / agent**:忽略 `interaction`(无人值守 / 模型填参);`confirmation` 对 agent 仍作 `requiresConfirmation` 元数据。
- 不要用 `interaction: "direct"` 掩盖需要用户填写的可编辑字段——宿主在 `auto` 下会因可编辑参数回落到 `form`;显式 `direct` + 可编辑字段时参数取 default/预填,作者须自觉。
@@ -1141,7 +1143,7 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件
| JSON 长文本 | `type: object`/`array`(以 JSON 字符串编辑)或 `textarea` | `display_type: json` / `textarea` |
| 数字 | `type: number` | `display_type: number` 或 INT/REAL/NUMERIC |
| 开关 | `type: boolean` | `display_type: boolean` |
| 枚举下拉 | `enum: [...]` | `options_json` 数组 |
| 枚举下拉 | `enum: [...]` + 可选 **`enumNames`**;有对应列时再加 `column` / 属性名对齐,复用列 `options_json` | `options_json` **数组** `{value,label}` |
| 关联下拉(Lookup) | 内联 `display_type: lookup` + `lookup`(`local_sql` / `skill_cli` / `external_api`;可选 `multiple`;可选 `presentation: "paged_table"`),或绑列 | 列侧仅同库 `local_sql`;多选存 `TEXT` 逗号分隔 id;分页小表只在 Action |
| 密码 | `sensitive: true` | 列 `sensitive` |
| 年份 | `display_type` 或 `format`: `year` | `display_type: year` → 存 `YYYY` |
@@ -1161,7 +1163,34 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件
**本版不做(勿宣传):** 浏览器内文件上传控件、复杂 `oneOf` / nested object 专用表单;`visibleWhen` 多条件 AND/OR 树、跨 Action 依赖、CRUD 新增/编辑对称显隐;Action 参数表单的列筛选对称。
(**Lookup 多选**已支持:同一 `lookup` + `multiple: true`,见上文;不是任意标签数组。**分页勾选小表**已支持:同一 `lookup` + `presentation: "paged_table"`,见「分页勾选小表」。)
(**本地路径选择**已支持:`file` / `directory` + 可选 `pathRoot`,见下节;提交值仍是本机绝对路径字符串,不是 multipart 上传。)
(**本地路径选择**已支持:`file` / `directory` + 可选 `pathRoot`,见下节;提交值仍是本机绝对路径字符串,不是 multipart 上传。)
(**静态枚举中文 label**已支持:Action `enumNames` 与列 `options_json` 数组对称,见下节「静态枚举 label」。)
### 静态枚举 label(`enum` / `enumNames` / 绑列)
固定小枚举(状态、船司代码、优先级等)**不要**走 Lookup。CRUD 用列 `options_json` 数组;Action 表单要与「新增记录」对齐中文展示时,按下面做。
**宿主解析优先序(高 → 低):**
1. **绑列 options**:字段通过 `column` / `columnMapping` / 属性名(含 camelCase→snake_case)对齐到当前表列,且该列已有解析后的 `options`(来自 `options_json` 数组或 lookup)→ 用列上的 `{value,label}`。
2. **`enumNames`**:与 `enum` 下标一一对应的展示文案;缺项或空串回退为该位 `enum` 原文。
3. **纯 `enum`**:无 label 时宿主只能显示代码值(体验差,新技能避免)。
```json
"carrierCode": {
"type": "string",
"title": "船司",
"column": "carrier_code",
"enum": ["maersk", "hmm"],
"enumNames": ["MAERSK 马士基", "HMM 现代商船"]
}
```
推荐:
- 表上已有同义枚举列 → **显式 `column`**(或属性名 = 列名)+ 列侧写好 `options_json`;`enum`/`enumNames` 可保留作无列上下文时的兜底(如 agent-only Action)。
- 无对应列、仅 Action 表单需要 → 只写 `enum` + `enumNames`(见 [`assets/examples/enum-names-action.example.json`](../assets/examples/enum-names-action.example.json))。
- **禁止**为了中文展示把固定枚举改成假 Lookup。
日期时间约定:
@@ -1235,7 +1264,8 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件
### 当前宿主稳定支持(摘要)
- 根:`object`;属性:`string` / `number` / `boolean`(`object`/`array` 仅作 JSON 多行编辑兼容,新技能慎用)
- `enum` / `default` / `required` / `sensitive` / `readOnly` / 可选 `revealInForm`
- `enum` / 可选 **`enumNames`** / `default` / `required` / `sensitive` / `readOnly` / 可选 `revealInForm`
- 可选 **`column`**:绑列复用 displayName 与 options(静态枚举或 lookup)
- `display_type` / `format`:`textarea` | **`year`** | **`year_month`** / `month` | `date` | `datetime_unix_seconds` | `url` | `email` | **`lookup`** | **`file`** | **`directory`**
- 可选 **`pathRoot`**(仅 `file` / `directory`):相对技能数据根的起始目录;省略默认 `{skill_data}/input`
- 字段内联 `lookup`(与 CRUD `options_json` lookup 对象同构;可选 `extra_column`、`multiple`)
@@ -1360,12 +1390,12 @@ CRUD 侧宿主义务与禁止事项见 [`SCHEMA.md`](SCHEMA.md)「表单与展
若还需要默认篇数,可在同一 `properties` 里为 `pickCount` 增加 `"default": 1`、`"minimum": 1`。
与 **`bind.selectionMode: "optional"`** 联用时:无勾选弹层展示 `pickCount`;有勾选则隐藏 `pickCount`、提交 `$selection.ids`。不要再拆第二个「只 pick / 只勾选」toolbar 按钮。见上文「勾选驱动模式」。
与 **`bind.selectionMode: "optional"`** 联用时:无勾选弹层展示 `pickCount`;有勾选则隐藏 `pickCount`、提交 `$selection.ids`。定时任务配置页同无勾选分支(不展示空「编号列表」)。不要再拆第二个「只 pick / 只勾选」toolbar / cron 按钮。见上文「勾选驱动模式」。
约定:
- `boolean` 在宿主中渲染为开关
- `enum` 在宿主中渲染为选择框
- `enum` 在宿主中渲染为选择框(或短列表分段控件);**展示文案**优先绑列 options,其次 `enumNames`,再次纯 `enum` 值
- `type: number` 渲染为数字输入
- `display_type`/`format: year` 渲染为年份选择;`year_month` / `month` 渲染为年月选择
- `display_type`/`format: date` 渲染为日期(日);`datetime_unix_seconds` 渲染为日期时间并按 **Unix 秒**提交

View File

@@ -37,6 +37,7 @@
- 不根据具体技能名称写特殊逻辑
- 可在技能安装/更新成功后静默调用 `python scripts/main.py init-db` 做幂等 ensure(内部即 `init_db()`);失败不影响安装结果
- 若技能启用了单元格呈现(见 [`CELL_PRESENTATION.md`](CELL_PRESENTATION.md)),读取旁路呈现数据并为格子 / 行 / 列 / 区域映射语义样式(`tone`);不猜测业务规则;整行色只涂表格行,不铺到详情字段
- **导入模板下拉(宿主能力)**:下载「Excel 模板」时,宿主按本表可导入列的元数据自动加 Excel 数据有效性下拉——凡列已有可选集合(`options_json` 静态枚举、schema 已解析的 lookup 选项、未写 options 的 `boolean` 默认「是/否」等)即加下拉;无选项的列仍为自由文本。下拉展示 **label**;导入写库时宿主(或 `replaces: import` 技能)再 **label → value**。CSV 模板**不能**带下拉,可选值仍写在导入弹窗「可导入字段说明」与 Excel「填写说明」页。技能**无需**自备带下拉的模板文件;把字段选项声明在 `_jiangchang_columns` 即可让所有技能受益。宿主不按技能名写死「只支持某几种业务字段」。
## 初始化入口
@@ -621,7 +622,7 @@ readonly = 0
| 层级 | 值 | 说明 |
|------|-----|------|
| 表级 `readonly` | `1` | 宿主数据管理只读展示,不提供新增/编辑/删除表单 |
| 表级 `readonly` | `1` | 宿主数据管理只读展示,不提供新增/编辑/导入与直写删除;若技能声明 `replaces: delete` 仍可显示删除并走 CLI |
| 相关业务字段 `editable` | `0` | 元数据权限只约束宿主 UI,不限制技能代码写库 |
模板**默认不建**此类审计表。过程看 `jiangchang.log`,进度/终态看任务中心,业务结果看业务表。
@@ -671,7 +672,7 @@ CREATE TABLE demo_items (
## 枚举字段 options_json
`options_json` 支持两种形态:
`options_json` 支持两种形态。正确声明后,数据管理「新增/编辑」下拉、列筛选、**以及 Excel 导入模板下拉**共用同一套选项(见上文「宿主负责」中的导入模板下拉)。
### 1)静态枚举(数组)
@@ -687,6 +688,8 @@ CREATE TABLE demo_items (
宿主据此渲染选择框;技能侧负责保证 JSON 合法且与物理字段取值一致。
**与 Action 表单对称:** 数据管理「新增/编辑」读列 `options_json`;Skill Action 弹窗用 `enum` + 可选 **`enumNames`**,或字段绑列(`column` / 属性名对齐)直接复用本列 options。宿主优先序:**绑列 options → enumNames → 纯 enum**。详见 [`ACTIONS.md`](ACTIONS.md)「静态枚举 label」。固定小枚举**不要**改成 Lookup。
### 2)跨表引用 lookup(对象,用于关联 id 字段)
当字段取值依赖同库另一张业务表时,`display_type` 设为 `lookup`,`options_json` 写对象(**不是**数组)。这是**展示与表单选择**契约,**不是** SQLite 外键。

View File

@@ -1,6 +1,6 @@
"""技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。"""
SKILL_SLUG = "your-skill-slug"
SKILL_VERSION = "1.0.121"
SKILL_VERSION = "1.0.124"
LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug"
PLATFORM_KIT_MIN_VERSION = "1.2.11"

View File

@@ -290,6 +290,29 @@ class TestActionsManifest(unittest.TestCase):
action_props = schema["$defs"]["action"]["properties"]
self.assertNotIn("visibleWhen", action_props)
def test_schema_defines_enum_names_on_input_property(self) -> None:
schema = _load_actions_schema()
props = schema["$defs"]["inputProperty"]["properties"]
self.assertIn("enum", props)
self.assertIn("enumNames", props)
self.assertEqual(props["enumNames"].get("type"), "array")
self.assertEqual(props["enumNames"].get("minItems"), 1)
self.assertIn("column", props)
def test_enum_names_example_exists_and_aligns_labels(self) -> None:
path = os.path.join(
get_skill_root(), "assets", "examples", "enum-names-action.example.json"
)
self.assertTrue(os.path.isfile(path), msg="enum-names example must exist")
with open(path, encoding="utf-8") as f:
example = json.load(f)
props = example["actions"][0]["inputSchema"]["properties"]
category = props["category"]
self.assertEqual(len(category["enum"]), len(category["enumNames"]))
self.assertEqual(category.get("column"), "category")
priority = props["priority"]
self.assertEqual(len(priority["enum"]), len(priority["enumNames"]))
def test_default_manifest_omits_visible_when(self) -> None:
for action in _load_actions_manifest()["actions"]:
properties = ((action.get("inputSchema") or {}).get("properties")) or {}
@@ -802,6 +825,9 @@ class TestActionsManifest(unittest.TestCase):
"已选择",
"revealInForm",
"映射只读",
"enumNames",
"静态枚举 label",
"绑列 options",
):
self.assertIn(marker, text, msg=f"ACTIONS.md missing {marker!r}")
self.assertNotIn(

View File

@@ -446,17 +446,27 @@ class TestDocsStandards(unittest.TestCase):
),
msg="lookup-paged-table.action.example.json missing",
)
self.assertTrue(
os.path.isfile(
os.path.join(get_skill_root(), "assets/examples/enum-names-action.example.json")
),
msg="enum-names-action.example.json missing",
)
checklist = self._read("development/CHECKLIST.md")
self.assertIn("skill_cli", checklist)
self.assertIn("A4-12", checklist)
self.assertIn("A4-13", checklist)
self.assertIn("enumNames", checklist)
self.assertIn("paged_table", checklist)
account_mgr = self._read("development/ACCOUNT_MANAGER.md")
self.assertIn("skill_cli", account_mgr)
schema = self._read("references/SCHEMA.md")
self.assertIn("skill_cli", schema)
self.assertIn("enumNames", schema)
schema_json = self._read("assets/schemas/skill-actions.schema.json")
self.assertIn("skill_cli", schema_json)
self.assertIn("paged_table", schema_json)
self.assertIn("enumNames", schema_json)
self.assertIn("page_size", schema_json)
self.assertIn('"skill"', schema_json)
@@ -488,6 +498,7 @@ class TestDocsStandards(unittest.TestCase):
self.assertIn("revealInForm", checklist)
self.assertIn("A4-9", checklist)
self.assertIn("selectionMode", checklist)
self.assertIn("定时任务配置页", checklist)
self.assertIn("A4-10", checklist)
self.assertIn("A4-11", checklist)
self.assertIn("bind.visibleWhen", checklist)
@@ -498,11 +509,14 @@ class TestDocsStandards(unittest.TestCase):
self.assertIn("selectionMode", runtime)
self.assertIn("bind.visibleWhen", runtime)
self.assertIn("用户可见文案", runtime)
self.assertIn("无表勾选入口按无勾选分支", runtime)
actions = self._read("references/ACTIONS.md")
self.assertIn("用户可见文案", actions)
self.assertIn("双受众", actions)
self.assertIn("行菜单显隐", actions)
self.assertIn("bind.visibleWhen", actions)
self.assertIn("无表勾选入口", actions)
self.assertIn("编号列表", actions)
def test_guarded_docs_do_not_reference_amazon_implementation(self) -> None:
forbidden = (