diff --git a/CHANGELOG.md b/CHANGELOG.md index 600e626..9966b62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ - 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节 - 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段 +## 1.0.72 + +- 澄清 `placements: "row"` 契约:表示数据管理**行级入口**;技能配置决定菜单项,宿主可呈现为操作列、行右键和/或行内「⋯」(同一批 Action,无独立菜单 DSL / `row-context-menu` placement) +- 更新 ACTIONS.md、SKILL_ACTION_RUNTIME、DEVELOPMENT 验收表与 skill-actions.schema 描述 + ## 1.0.71 - 文档对齐:Skill Action `sync` 默认超时约 **60s**(`SKILL_ACTION_SYNC_TIMEOUT_MS`);接近或超过约 60s 的任务应标 `async` diff --git a/SKILL.md b/SKILL.md index 215ced3..e0b7cc3 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 技能开发模板(通用业务版) description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。" -version: 1.0.71 +version: 1.0.72 author: 深圳匠厂科技有限公司 metadata: openclaw: @@ -32,7 +32,7 @@ allowed-tools: ### 架构铁律(先读) - **单业务内核、多入口**:数据管理 / 定时任务 / Agent / 技能详情 / 直接 CLI 必须复用同一 domain service;禁止按入口复制业务逻辑,禁止按 `source` 分叉业务行为。 -- **`placements`**:只决定 Action **出现在哪里**(toolbar / row / batch / cron / agent / skill-detail)。数据管理技能按钮顺序见 `actions` **数组相对顺序**(详见 `references/ACTIONS.md`),无独立 sortOrder。 +- **`placements`**:只决定 Action **出现在哪里**(toolbar / row / batch / cron / agent / skill-detail)。其中 `row` 表示**行级入口**(宿主可呈现为操作列、行右键、行内「⋯」等;技能配什么就显示什么,无独立菜单 DSL)。数据管理技能按钮顺序见 `actions` **数组相对顺序**(详见 `references/ACTIONS.md`),无独立 sortOrder。 - **`bind.tables`**:只决定数据管理出现在哪些表;含 `toolbar` 时**必须**显式非空绑定。 - **`executionProfile`**:只决定执行方式——`sync` 当场返回结果,`async` 进**任务中心**。与 placements / 入口**无关**。心智上多数为 sync,仅长任务 / RPA 标 async;宿主省略该字段时按 sync。每个 Action **仍必须**显式写 `sync` 或 `async`。 - **同步数据**写技能本地库、不生成导出文件;**导出当前表**由宿主数据管理负责;特殊业务报告才另做 `export-*`。 diff --git a/assets/schemas/skill-actions.schema.json b/assets/schemas/skill-actions.schema.json index f3e13a0..fd16323 100644 --- a/assets/schemas/skill-actions.schema.json +++ b/assets/schemas/skill-actions.schema.json @@ -20,14 +20,14 @@ "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/action" }, - "description": "Action 列表。同一 placement(toolbar/row/batch)下,宿主按本数组中匹配项的相对顺序全部直接渲染技能按钮(无「更多操作」溢出);调整顺序即调整数组先后。无独立 sortOrder 字段。宿主内置刷新/导出/查看等不参与本顺序。表顶栏宽时左右横排,窄时左右分栏且栏内竖排。" + "description": "Action 列表。同一 placement(toolbar/row/batch)下,宿主按本数组中匹配项的相对顺序展示。toolbar/batch:表顶栏全部直接展示(无「更多操作」溢出)。row:行级入口,宿主可呈现为操作列、行右键和/或行内「⋯」(同一批 Action、同一顺序);不在本字段配置排序、截断或菜单树。调整顺序即调整数组先后。无独立 sortOrder 字段。宿主内置刷新/导出/查看等不参与本顺序。表顶栏宽时左右横排,窄时左右分栏且栏内竖排。" } }, "$defs": { "placement": { "type": "string", "enum": ["toolbar", "row", "batch", "cron", "agent", "skill-detail"], - "description": "稳定支持 toolbar/row/batch/cron/agent/skill-detail(对齐匠厂宿主)。placements 与 executionProfile 正交,不做条件限制。" + "description": "稳定支持 toolbar/row/batch/cron/agent/skill-detail(对齐匠厂宿主)。row=行级入口(操作列/行右键/⋯ 等由宿主呈现,无独立 row-context-menu placement)。placements 与 executionProfile 正交,不做条件限制。" }, "mutationKind": { "type": "string", @@ -167,7 +167,7 @@ "type": "array", "minItems": 0, "items": { "$ref": "#/$defs/placement" }, - "description": "决定 Action 出现在哪里;与 executionProfile 正交。仅 replaces 接管默认 CRUD 时可为空数组。数据管理 toolbar/row/batch 的按钮顺序由顶层 actions 数组相对顺序决定;表顶栏全部直接展示(无溢出菜单),不在本字段配置排序或截断。" + "description": "决定 Action 出现在哪里;与 executionProfile 正交。仅 replaces 接管默认 CRUD 时可为空数组。数据管理 toolbar/row/batch 的顺序由顶层 actions 数组相对顺序决定。表顶栏 toolbar/batch 全部直接展示(无溢出菜单);row 为行级入口(操作列/行右键/⋯),不在本字段配置排序、截断或菜单树。" }, "replaces": { "$ref": "#/$defs/mutationKind" }, "entrypoint": { "$ref": "#/$defs/entrypoint" }, diff --git a/development/DEVELOPMENT.md b/development/DEVELOPMENT.md index f82f9e2..17bdbce 100644 --- a/development/DEVELOPMENT.md +++ b/development/DEVELOPMENT.md @@ -841,7 +841,7 @@ uses: client-jiangchang/jiangchang-platform-kit/.github/workflows/reusable-relea |-------------------------|----------------|--------------| | **新建任务**(对话 Agent) | `placements` 含 `agent`;或短查询走共享 Python CLI | 自然语言能触发主流程;长任务 / RPA 须走 `run_skill_action`,禁止 bash 干等 | | **数据管理 · 表顶栏** | `placements` 含 `toolbar`(须合法非空 `bind.tables`) | 左侧能看到本技能库表;表顶栏出现按钮;点按行为符合预期 | -| **数据管理 · 行内** | `placements` 含 `row`(建议 `bind.tables` + `bind.inputMapping` 预填主键) | 行内操作链接可见(需有主键列);点按后入参/行为正确 | +| **数据管理 · 行级** | `placements` 含 `row`(建议 `bind.tables` + `bind.inputMapping` 预填主键) | 操作列和/或行右键(及可选「⋯」)出现本技能行级 Action(需有主键列);点按后入参/行为与壳无关、均正确 | | **数据管理 · 批量** | `placements` 含 `batch` | 勾选行后批量按钮可用;无勾选时禁用;批量行为正确 | | **定时任务** | `placements` 含 `cron`(创建时选「技能直调」) | 能选到本技能 Action、保存并触发;到点或「立即运行」行为正确 | | **任务中心** | 不是 placement;由 `executionProfile: "async"` 决定是否进 Job | 长任务出现进度 / 可取消;来源标签与触发入口一致 | diff --git a/development/SKILL_ACTION_RUNTIME.md b/development/SKILL_ACTION_RUNTIME.md index 28a3973..8e84412 100644 --- a/development/SKILL_ACTION_RUNTIME.md +++ b/development/SKILL_ACTION_RUNTIME.md @@ -66,7 +66,7 @@ |-------------------------|-------------------|--------|--------------| | **新建任务**(对话 Agent) | `agent` | `placements` 含 `agent`;`run_skill_action` | 侧栏「新建任务」→ 对话触发 | | **数据管理 · 顶栏** | `data-management` | `toolbar` + 必填 `bind.tables` | 侧栏「数据管理」→ 表顶栏按钮 | -| **数据管理 · 行内** | `data-management` | `row`(建议 `bind.tables` + `inputMapping`) | 同行操作链接(需主键) | +| **数据管理 · 行级** | `data-management` | `row`(建议 `bind.tables` + `inputMapping`) | 操作列和/或**行右键**(及可选「⋯」)可见并触发(需主键);技能配什么就显示什么 | | **数据管理 · 批量** | `data-management` | `batch` | 勾选行后点批量按钮 | | **定时任务** | `cron` | `placements` 含 `cron` | 侧栏「定时任务」→「技能直调」 | | **任务中心** | (各入口触发的 Job) | `executionProfile: "async"` | 侧栏「任务中心」查看进度 / 取消;**不是** placement | diff --git a/references/ACTIONS.md b/references/ACTIONS.md index e0290d1..b10035c 100644 --- a/references/ACTIONS.md +++ b/references/ACTIONS.md @@ -80,7 +80,7 @@ Action 是**可选能力**: | 字段 / 层 | 只决定什么 | 不决定什么 | |-----------|------------|------------| -| **`placements`** | Action **出现在哪里**(toolbar / row / batch / cron / agent / skill-detail) | 不决定 sync/async,不决定点了是否弹窗 | +| **`placements`** | Action **出现在哪里**(toolbar / row / batch / cron / agent / skill-detail;`row`=行级入口,壳由宿主呈现) | 不决定 sync/async,不决定点了是否弹窗,不决定行级用操作列还是右键 | | **`replaces`** | **可选**:接管数据管理默认「新增 / 编辑 / 删除」 | 不强制;无配置时宿主仍直写 SQLite | | **`bind.tables`** | 数据管理里出现在**哪些业务表** | 不决定业务实现 | | **`executionProfile`** | 宿主是**同步等待**还是**异步 Job** | 不限制可展示入口,不决定是否弹窗 | @@ -352,12 +352,20 @@ HINT: | 值 | 含义 | |----|------| | `toolbar` | 数据管理表顶栏技能按钮(须配合 `bind.tables`) | -| `row` | 数据管理行内操作(建议 `bind.tables` + `inputMapping`;表需有主键) | +| `row` | 数据管理**行级入口**(建议 `bind.tables` + `inputMapping`;表需有主键)。技能声明后,由宿主呈现为操作列链接、**行右键菜单**和/或行内「⋯」等壳;**不**新增 `row-context-menu` 等 placement | | `batch` | 数据管理批量操作(需勾选行;无勾选时宿主禁用按钮) | | `skill-detail` | 技能详情页直调(与安装/四 Tab 同属技能市场详情;已声明则须自测) | | `agent` | Agent 可直接调用(`run_skill_action`) | | `cron` | 定时任务「技能直调」 | +### 行级入口 `row`(宿主呈现契约) + +- **技能决定有什么**:`placements` 含 `"row"`(且通过 `bind.tables` / policy 等过滤)的 Action,构成该表行的技能菜单项集合;配什么就出现什么。 +- **宿主决定怎么摆**:可用操作列、行右键、行内「⋯」等呈现**同一批** Action;点击均走同一 `launch`(`placement: "row"`),`interaction` / `executionProfile` 与壳无关。 +- **顺序**:各壳内技能项顺序 = 下方「数据管理技能按钮顺序」契约(`actions` 数组相对顺序)。 +- **宿主内置项**:查看 / 编辑 / 删除由宿主提供,**不是**技能 `actions.json` 配置出来的;若出现在行右键,须与技能项分组(例如分隔线后),且不得要求技能再配一份菜单 DSL。 +- **禁止**:为右键单独发明 placement、菜单注册表或第二套 Action 列表。 + ### 数据管理技能按钮顺序(宿主正式契约) 宿主**没有**单独的 `sortOrder` / `uiOrder` 字段。同一 `placement`(`toolbar` / `row` / `batch`)下,技能按钮的展示顺序 = `actions` 数组中**匹配该项 placement(且通过 `bind.tables` 过滤)的相对先后**。 @@ -369,8 +377,8 @@ HINT: 3. 同一 Action 可同时挂多个 placement;它在各入口的位置,分别是该入口匹配子集里的相对位置。 4. **宿主内置按钮不参与本契约、位置固定**: - 表顶栏右侧:删除(有勾选时)/ 刷新 / 新增 / 导入 / 导出 —— 技能 toolbar/batch 按钮在左侧,不能与右侧内置按钮混排。 - - 行内「操作」列:技能 `row` 按钮在前;其后固定为宿主「查看」→(非只读)「编辑」→「删除」。 -5. **表顶栏全部直接展示,无「更多操作」溢出菜单**:匹配到的 toolbar/batch 技能按钮一律渲染(顺序仍按本契约)。 + - 行级:技能 `row` 项按本顺序出现在操作列 / 行右键(及可选「⋯」)中;宿主「查看」→(非只读)「编辑」→「删除」为内置项,位置由宿主固定(操作列常在技能项之后;右键中可与技能项分组)。 +5. **表顶栏全部直接展示,无「更多操作」溢出菜单**:匹配到的 toolbar/batch 技能按钮一律渲染(顺序仍按本契约)。**行级**不以「顶栏溢出菜单」模型截断;行右键是 `row` 的正式呈现壳之一,不是 toolbar 式「更多操作」截断。 6. **表顶栏宽窄布局(宿主行为,技能无需配置)**: - 够宽:左右各横排一行(左技能按钮 + 右宿主工具)。 - 不够宽:保持左右分栏,栏内按钮上下竖排(左栏技能、右栏刷新/导出等)。 @@ -378,8 +386,9 @@ HINT: 禁止: - 臆造 `sortOrder` / `order` / `priority` 等字段指望宿主排序(模板 Schema `additionalProperties: false` 会拒收)。 -- 依赖或宣传「更多操作」溢出菜单(宿主已取消该能力)。 +- 依赖或宣传表顶栏「更多操作」溢出菜单(宿主已取消该能力)。 - 把「表格行数据默认排序」与按钮顺序混淆——行排序见 [`SCHEMA.md`](SCHEMA.md) 的 `default_sort_json`。 +- 新增 `row-context-menu` 等 placement,或要求技能再维护一份与 `row` 平行的菜单清单。 ### Action 类型 × placements(常见示例,不是限制) diff --git a/scripts/util/constants.py b/scripts/util/constants.py index c923a56..139c8dd 100644 --- a/scripts/util/constants.py +++ b/scripts/util/constants.py @@ -1,6 +1,6 @@ """技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。""" SKILL_SLUG = "your-skill-slug" -SKILL_VERSION = "1.0.71" +SKILL_VERSION = "1.0.72" LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug" PLATFORM_KIT_MIN_VERSION = "1.2.2" diff --git a/tests/test_actions_manifest.py b/tests/test_actions_manifest.py index 62c12cf..1a1e552 100644 --- a/tests/test_actions_manifest.py +++ b/tests/test_actions_manifest.py @@ -514,6 +514,8 @@ class TestActionsManifest(unittest.TestCase): "数组相对顺序", "全部直接展示", "左右分栏", + "行级入口", + "行右键", ): self.assertIn(marker, text, msg=f"ACTIONS.md missing {marker!r}") self.assertNotIn( @@ -521,6 +523,17 @@ class TestActionsManifest(unittest.TestCase): text, msg="ACTIONS.md must not document removed overflow more-menu truncation", ) + self.assertIn( + "新增 `row-context-menu` 等 placement", + text, + msg="ACTIONS.md must forbid inventing a separate row-context-menu placement", + ) + placement_enum = _load_actions_schema().get("$defs", {}).get("placement", {}).get("enum") or [] + self.assertNotIn( + "row-context-menu", + placement_enum, + msg="skill-actions.schema must not add row-context-menu to placements enum", + ) for forbidden in ( "数据管理 toolbar " + "只挂", "toolbar " + "只放 async",