@coda-console/protocol 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ Coda 与插件之间的约定,Coda 和插件都引用它,独立演进:
15
15
 
16
16
  流程方言的 **卡片字段**由 `workflow/fields.json` 定义:七种字段各能写哪些属性、必填项、文字长度与单行限制、路径与网址、视图参数、输入框与密钥选项;`values.json` 的 `Field` 引用它,`Fields` 声明读出 JSON 字段列表的表达式,`UserTask.children` 限定最多 12 个静态字段、id 不重复,以及全部字段已知时答复的 `fields` 只能引用输入字段(含按住出现的答复)。
17
17
 
18
- 定义和运行时共用这一份 schema。`x-deferred` 包住一个 schema:读定义时,文字先检查 FEEL,表达式或含 `{{ … }}` 的模板留到打开任务后查;运行时只按包住的 schema 严格检查,不再把结果当表达式。只有内容属性使用它,`type`、`id`、布尔值、枚举和 `maxLength` 不放宽。另有 `x-length`(沿用 Coda 的 UTF-16 长度,可用 `{ "property": "maxLength" }` 读取同一对象的上限)、`x-json`(解析 JSON 文字或检查 JSON 值,按序列化后的 UTF-8 字节数限制大小);`absolute-path`、`https-url` 两个 format 按本机路径与 URL 解析器检查。已有的 `x-ref` 增加 `key`(按数组元素的属性引用)和 `split`(逐个检查分隔后的名字)。这些操作都不改写输入。
18
+ 定义和运行时共用这一份 schema。`x-deferred` 包住一个 schema:读定义时,文字先检查 FEEL,表达式或含 `{{ … }}` 的模板留到打开任务后查;运行时只按包住的 schema 严格检查,不再把结果当表达式。只有内容属性使用它,`type`、`id`、布尔值、枚举和 `maxLength` 不放宽。另有 `x-length`(沿用 Coda 的 UTF-16 长度,可用 `{ "property": "maxLength" }` 读取同一对象的上限)、`x-json`(解析 JSON 文字或检查 JSON 值,按序列化后的 UTF-8 字节数限制大小);`absolute-path`、`https-url`、`link-url` 三个 format 按本机路径与 URL 解析器检查;`link-url` 接受 https 网址或 `action=download-manifest` 且 `url` 解码后为 https 网址的 `itms-services:` 安装链接。已有的 `x-ref` 增加 `key`(按数组元素的属性引用)和 `split`(逐个检查分隔后的名字)。这些操作都不改写输入。
19
19
 
20
20
  `fieldProblem(field, where)` 检查一个已求值的字段;`fieldsProblem(fields, where)` 检查展开并应用 `host`/`dir` 后的数组,复用同一份字段 schema、数量和唯一性规则。两者合法时返回 `null`,否则返回「位置:说明」;`where` 是调用方给出的完整位置。schema 的 `default` 仅作标注:默认值填充、去空白、域名转小写、`args` 解析后的保留、表达式求值、动态字段展开和用户答复的处理仍由 Coda 完成。`coda:fields` 的 `host`/`dir` 是可能被覆盖或忽略的备用值,定义时只检查 FEEL,合并后才检查实际字段。动态字段展开后,答复的输入引用仍须由 Coda 检查。
21
21
 
@@ -5,7 +5,7 @@
5
5
  2.2.0 按[第 7 步方案](https://github.com/coda-console/coda/issues/2078#issuecomment-6559423071)补齐流程接入:
6
6
  **无资源或一个资源的一单位**,可独占所申请资源;多单位、多资源原子申请仍未开放。
7
7
 
8
- 协议对象版本 `protocolVersion: 1`、本目录的 v1、npm 包版本 2.4.0 和插件清单的 v2 分开演进。
8
+ 协议对象版本 `protocolVersion: 1`、本目录的 v1、npm 包版本 2.5.0 和插件清单的 v2 分开演进。
9
9
  本次只增加契约;不改变 `contributes.executors`,也不宣称 host、scheduler、空间引用解析或账本接口已经实现。
10
10
 
11
11
  ## 定义与登记
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coda-console/protocol",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Coda 的协议:插件清单的类型(JSON Schema)、通用校验器、流程方言与 Agent 接入协议",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -7,6 +7,14 @@
7
7
  "properties": {
8
8
  "id": {"$ref": "common.json#/$defs/id", "description": "插件 ID:小写字母、数字和「-」,以字母开头,至多 40 个字符;不写就用 name"},
9
9
  "name": {"type": "string"},
10
+ "description": {"description": "一句话简介:插件列表里只显示一行,20 字以内为宜;更多的说明写在插件目录的 README.md,插件页里显示", "type": "string"},
11
+ "icon": {
12
+ "description": "插件的图标:插件目录里的 PDF(light 必填,dark 与 template 可选,同 Agent 的图标),或 SF Symbols 的符号画在系统色的底上(symbol 与 color);客户端裁成圆角方块。不写时,只带一个 Agent 的插件用那个 Agent 的图标,其余用分类的默认图标",
13
+ "type": "object",
14
+ "if": {"required": ["symbol"]},
15
+ "then": {"$ref": "#/$defs/symbolIcon"},
16
+ "else": {"$ref": "#/$defs/fileIcon"}
17
+ },
10
18
  "categories": {"description": "分类:文本的数组,第一个是插件页里归的类", "type": "array", "items": {"type": "string"}},
11
19
  "coda": {
12
20
  "description": "Coda 宿主的安装要求;不写 channels 就不限制后端通道",
@@ -49,6 +57,23 @@
49
57
  "propertyNames": {"description": "contributes 的键:字母和数字,以小写字母开头", "pattern": "^[a-z][A-Za-z0-9]{0,39}$"}
50
58
  }
51
59
  },
60
+ "$defs": {
61
+ "fileIcon": {
62
+ "type": "object",
63
+ "properties": {"light": {"$ref": "agents.json#/$defs/icon"}, "dark": {"$ref": "agents.json#/$defs/icon"}, "template": {"description": "单色图标:按文字颜色画", "type": "boolean"}},
64
+ "required": ["light"],
65
+ "additionalProperties": false
66
+ },
67
+ "symbolIcon": {
68
+ "type": "object",
69
+ "properties": {
70
+ "symbol": {"description": "SF Symbols 的符号名,如 key.fill", "type": "string", "maxLength": 100, "pattern": "^[a-z0-9]+(\\.[a-z0-9]+)*$"},
71
+ "color": {"description": "底色:系统色 red、orange、yellow、green、mint、teal、cyan、blue、indigo、purple、pink、brown、gray 之一", "enum": ["red", "orange", "yellow", "green", "mint", "teal", "cyan", "blue", "indigo", "purple", "pink", "brown", "gray"]}
72
+ },
73
+ "required": ["symbol", "color"],
74
+ "additionalProperties": false
75
+ }
76
+ },
52
77
  "if": {"properties": {"activationEvents": {"minItems": 1}}, "required": ["activationEvents"]},
53
78
  "then": {"required": ["main"], "description": "写了 activationEvents 的插件须有 main"}
54
79
  }
@@ -158,7 +158,7 @@
158
158
  "x-deferred": {
159
159
  "allOf": [
160
160
  {"type": "string", "pattern": "^\\s*\\S(?:[^\\r\\n]*\\S)?\\s*$", "x-length": 2000, "description": "href 须为一行、1–2000 个字"},
161
- {"format": "https-url", "description": "href 须为 https 网址"}
161
+ {"format": "link-url", "description": "href 须为 https 网址或 iOS 安装链接(itms-services,清单为 https)"}
162
162
  ]
163
163
  }
164
164
  }
@@ -52,6 +52,12 @@ export function jsonFits(value, max) {
52
52
  export function valueKeywords(ajv, { feelProblem, isExpression }) {
53
53
  ajv.addFormat('absolute-path', value => isAbsolute(value.trim()));
54
54
  ajv.addFormat('https-url', value => { try { return new URL(value.trim()).protocol === 'https:'; } catch { return false; } });
55
+ ajv.addFormat('link-url', value => {
56
+ const url = URL.parse(value.trim());
57
+ return url?.protocol === 'https:' || (url?.protocol === 'itms-services:'
58
+ && url.searchParams.get('action') === 'download-manifest'
59
+ && URL.parse(url.searchParams.get('url'))?.protocol === 'https:');
60
+ });
55
61
  ajv.addKeyword({
56
62
  keyword: 'x-length', type: 'string', schemaType: ['number', 'object'], errors: true,
57
63
  metaSchema: { anyOf: [{ type: 'integer', minimum: 0 }, { type: 'object', properties: { property: { type: 'string' } }, required: ['property'], additionalProperties: false }] },