@josephyan/qingflow-cli 1.1.11 → 1.1.13

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
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @josephyan/qingflow-cli@1.1.11
6
+ npm install @josephyan/qingflow-cli@1.1.13
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-cli@1.1.11 qingflow
12
+ npx -y -p @josephyan/qingflow-cli@1.1.13 qingflow
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-cli",
3
- "version": "1.1.11",
3
+ "version": "1.1.13",
4
4
  "description": "Human-friendly Qingflow command line interface for auth, record operations, import, tasks, and stable builder flows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "1.1.11"
7
+ version = "1.1.13"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -18,6 +18,7 @@ portal list/get if updating -> verify apps/views/charts -> portal apply -> porta
18
18
 
19
19
  - Use `--dash-key` for updates and do not send `package_id`.
20
20
  - Use `patch_sections[]` for targeted section changes when possible.
21
+ - `patch_sections[]` selectors may use `order`, `chart_ref.chart_id`, `chart_ref.chart_key`, or `view_ref.view_key`; chart sections read back from portal often only include `chart_id`, so patching by `chart_id` is valid and does not require `app_key`.
21
22
  - If using a business-entry grid, include real `items`; do not submit an empty entry container.
22
23
  - Validate referenced `chart_key`, `chart_id`, `view_key`, or `app_key` before claiming the portal is complete.
23
24
 
@@ -16,11 +16,13 @@ contract -> app get fields -> app get flow -> member/role lookup -> flow apply -
16
16
 
17
17
  ## Recommended write path
18
18
 
19
+ - For normal agent-authored workflows, use the public path: `--nodes-file` + `--transitions-file`.
20
+ - `--spec-file` is an advanced raw backend WorkflowSpec path. Do not put public node aliases such as `start` / `approve` / `end` into `--spec-file`.
19
21
  - Start from a preset when possible: `basic_approval` or `basic_fill_then_approve`.
20
22
  - Patch preset node ids instead of adding duplicate nodes:
21
23
  - `basic_approval` -> `approve_1`
22
24
  - `basic_fill_then_approve` -> `fill_1`, `approve_1`
23
- - Use `patch_nodes[]` for targeted updates to an existing flow.
25
+ - Use `patch_nodes[]` for targeted updates to an existing flow. Node ids come from `builder flow get` readback, not from the original public `nodes-file` ids after the backend has assigned workflow node ids.
24
26
  - Do not mix `patch_nodes` and full `spec` in the same call.
25
27
 
26
28
  ## Supported public node types
@@ -19,7 +19,9 @@
19
19
  |------|------|
20
20
  | `qingflow builder flow schema --json` | 获取最新 WorkflowSpecDTO JSON Schema |
21
21
  | `qingflow builder flow get --app-key <KEY>` | 读取当前工作流 spec |
22
- | `qingflow builder flow apply --app-key <KEY> --spec-file <FILE>` | 部署/更新工作流 |
22
+ | `qingflow --json builder flow apply --app-key <KEY> --nodes-file <NODES> --transitions-file <TRANSITIONS>` | 主链路:部署/更新 public 工作流 |
23
+ | `qingflow --json builder flow apply --app-key <KEY> --patch-nodes-file <PATCH>` | 局部修改现有节点 |
24
+ | `qingflow --json builder flow apply --app-key <KEY> --spec-file <FILE>` | 高级链路:部署 raw backend WorkflowSpec,不用于 public node aliases |
23
25
  | `qingflow builder member search --query <关键词>` | 搜索成员 |
24
26
  | `qingflow builder role search --keyword <关键词>` | 搜索角色 |
25
27
  | `qingflow --json app get --app-key <KEY>` | 获取应用信息(字段列表等) |
@@ -33,7 +35,7 @@
33
35
  | 在范围内 | 超出范围 |
34
36
  |----------|----------|
35
37
  | 基于已有应用搭建工作流 | 从零创建应用 |
36
- | 声明式 WorkflowSpec 生成与 apply | 操作复杂命令拼接 |
38
+ | public nodes/transitions 生成与 apply | 操作复杂命令拼接 |
37
39
  | 分支条件(gateway + autoJudges)配置 | 后端不支持的高级特性 |
38
40
  | 审批/填写/抄送/自动化节点配置 | 修改字段定义 |
39
41
  | 成员/角色搜索用于节点负责人 | 组织架构管理 |
@@ -19,9 +19,19 @@
19
19
  | 修改条件 | 同一条边内改 condition | 删除边再新建 |
20
20
  | 调整流转 | 修改边的 from/to | 改节点 ID 来适配 |
21
21
 
22
- ## 使用 diff 脚本辅助判断
22
+ ## 使用 patch_nodes 优先
23
23
 
24
- 在构建新 spec 后、apply 前,使用 diff 脚本对比新旧 spec
24
+ 如果只是改节点名称、负责人、局部 attrs,优先使用 `patch_nodes[]`,节点 id `builder flow get` 的 `spec.nodes[]` 读取:
25
+
26
+ ```json
27
+ [
28
+ {"id": "89160906", "set": {"name": "需求评审(局部改)"}}
29
+ ]
30
+ ```
31
+
32
+ ## raw spec 更新时使用 diff 脚本辅助判断
33
+
34
+ 只有在需要提交 raw backend `--spec-file` 时,才在 apply 前使用 diff 脚本对比新旧 spec:
25
35
 
26
36
  ```bash
27
37
  python3 scripts/diff_flow_spec.py tmp/current_flow.json tmp/flow_spec.json
@@ -29,7 +39,7 @@ python3 scripts/diff_flow_spec.py tmp/current_flow.json tmp/flow_spec.json
29
39
 
30
40
  输出会显示删除的节点/边、新增的节点/边、修改的节点/边,并自动评估是否符合最小修改原则。
31
41
 
32
- 验证脚本也支持在更新模式下进行最小修改原则校验:
42
+ 验证脚本也支持在 raw spec 更新模式下进行最小修改原则校验:
33
43
 
34
44
  ```bash
35
45
  python3 scripts/validate_flow_spec.py \
@@ -1,4 +1,4 @@
1
- # 阶段 3:获取 Schema + 构建 Spec
1
+ # 阶段 3:获取 Schema + 构建流程输入
2
2
 
3
3
  ## 3.1 获取当前工作流 Schema
4
4
 
@@ -16,7 +16,7 @@ qingflow --json builder flow get --app-key <APP_KEY> > tmp/current_flow.json
16
16
 
17
17
  从返回的 `spec` 中提取 `nodes` 和 `edges` 作为修改基础。
18
18
 
19
- **更新模式下**:构建新 spec 后,用 diff 脚本确认变更范围是否符合预期:
19
+ **更新模式下**:如果走 `patch_nodes[]`,直接使用读回的 `spec.nodes[].id` 做局部修改;如果确实需要 raw backend `--spec-file`,再用 diff 脚本确认变更范围是否符合预期:
20
20
 
21
21
  ```bash
22
22
  python3 scripts/diff_flow_spec.py tmp/current_flow.json tmp/flow_spec.json
@@ -24,9 +24,45 @@ python3 scripts/diff_flow_spec.py tmp/current_flow.json tmp/flow_spec.json
24
24
 
25
25
  新建场景可跳过此步。
26
26
 
27
- ## 3.3 构建 WorkflowSpec
27
+ ## 3.3 推荐:构建 public nodes / transitions
28
28
 
29
- 按照以下结构构建 `spec.json`:
29
+ 智能体主链路不要直接手写 raw backend `WorkflowSpec`。推荐写两个数组文件:
30
+
31
+ `tmp/flow_nodes.json`
32
+
33
+ ```json
34
+ [
35
+ {"id": "start", "type": "start", "name": "提交申请"},
36
+ {"id": "approve_1", "type": "approve", "name": "部门经理审批", "role_names": ["部门经理"]},
37
+ {"id": "end", "type": "end", "name": "结束"}
38
+ ]
39
+ ```
40
+
41
+ `tmp/flow_transitions.json`
42
+
43
+ ```json
44
+ [
45
+ {"from": "start", "to": "approve_1"},
46
+ {"from": "approve_1", "to": "end"}
47
+ ]
48
+ ```
49
+
50
+ 提交时使用:
51
+
52
+ ```bash
53
+ qingflow --json builder flow apply \
54
+ --app-key <APP_KEY> \
55
+ --nodes-file tmp/flow_nodes.json \
56
+ --transitions-file tmp/flow_transitions.json \
57
+ --publish \
58
+ > tmp/flow_apply.json
59
+ ```
60
+
61
+ ## 3.4 高级:raw backend WorkflowSpec
62
+
63
+ `--spec-file` 只用于已经从 `builder flow get` 读回并理解的 raw backend spec。不要把 `start` / `approve` / `fill` / `end` 这类 public node alias 放进 `--spec-file`。
64
+
65
+ raw backend spec 示例:
30
66
 
31
67
  ```json
32
68
  {
@@ -116,7 +152,7 @@ python3 scripts/diff_flow_spec.py tmp/current_flow.json tmp/flow_spec.json
116
152
  }
117
153
  ```
118
154
 
119
- ## 节点类型速查
155
+ ## raw backend 节点类型速查
120
156
 
121
157
  | type | 说明 | 必要 attrs |
122
158
  |------|------|-----------|
@@ -154,9 +190,23 @@ OR-of-AND 二维数组:
154
190
 
155
191
  **judgeType 常用值**:`equals`, `not_equals`, `equals_any`, `includes`, `greater_than` 等(共21种,详见 schema)。
156
192
 
157
- ## 3.4 保存 Spec 到文件
193
+ ## 3.5 局部修改 patch_nodes
194
+
195
+ 局部修改现有流程时,先 `builder flow get`,使用读回 `spec.nodes[].id`:
158
196
 
159
- 将构建好的完整 Spec 以 JSON 格式保存到文件 `tmp/flow_spec.json`,确保使用 UTF-8 编码、缩进格式化,以便后续验证和 apply 使用。
197
+ ```json
198
+ [
199
+ {"id": "89160906", "set": {"name": "需求评审(局部改)"}}
200
+ ]
201
+ ```
202
+
203
+ ```bash
204
+ qingflow --json builder flow apply \
205
+ --app-key <APP_KEY> \
206
+ --patch-nodes-file tmp/flow_patch_nodes.json \
207
+ --publish \
208
+ > tmp/flow_patch_apply.json
209
+ ```
160
210
 
161
211
  ---
162
212
 
@@ -1,13 +1,20 @@
1
- # 阶段 4:验证 Spec
1
+ # 阶段 4:验证流程输入
2
2
 
3
- 使用本 Skill 自带的验证脚本:
3
+ 主链路 `--nodes-file + --transitions-file` 由 CLI 模型校验 public node type、边引用和角色/成员解析。提交前至少检查:
4
+
5
+ - `nodes[].id` 唯一;
6
+ - `transitions[].from/to` 都能在 nodes 中找到;
7
+ - 节点类型只用 `start`、`approve`、`fill`、`copy`、`webhook`、`end`;
8
+ - 审批/填写节点有明确 `member_names`、`member_ids`、`role_names` 或 `role_ids`。
9
+
10
+ 只有 raw backend `--spec-file` 才使用本 Skill 自带的 WorkflowSpec 验证脚本:
4
11
 
5
12
  ```bash
6
- # 新建模式
13
+ # raw spec 新建模式
7
14
  python3 scripts/validate_flow_spec.py \
8
15
  tmp/flow_spec.json --schema tmp/flow_schema.json
9
16
 
10
- # 更新模式(同时校验最小修改原则)
17
+ # raw spec 更新模式(同时校验最小修改原则)
11
18
  python3 scripts/validate_flow_spec.py \
12
19
  tmp/flow_spec.json --schema tmp/flow_schema.json --previous tmp/current_flow.json
13
20
  ```
@@ -24,7 +31,7 @@ python3 scripts/validate_flow_spec.py \
24
31
 
25
32
  ## 验证不通过时的处理
26
33
 
27
- 根据错误信息修正 spec,重新验证,直到全部通过再进入 apply。
34
+ public 输入根据 CLI 错误修正 nodes/transitions;raw spec 根据验证脚本错误修正 spec,重新验证,直到全部通过再进入 apply。
28
35
 
29
36
  ---
30
37
 
@@ -2,11 +2,27 @@
2
2
 
3
3
  ## 5.1 部署工作流
4
4
 
5
+ 推荐主链路:
6
+
7
+ ```bash
8
+ qingflow --json builder flow apply \
9
+ --app-key <APP_KEY> \
10
+ --nodes-file tmp/flow_nodes.json \
11
+ --transitions-file tmp/flow_transitions.json \
12
+ --publish \
13
+ > tmp/flow_apply.json
14
+ ```
15
+
16
+ `--spec-file` 只用于 raw backend WorkflowSpec;普通智能体生成的 `start` / `approve` / `end` public nodes 必须走 `--nodes-file + --transitions-file`。
17
+
18
+ 局部修改已存在节点:
19
+
5
20
  ```bash
6
- qingflow builder flow apply \
21
+ qingflow --json builder flow apply \
7
22
  --app-key <APP_KEY> \
8
- --spec-file tmp/flow_spec.json \
9
- --publish
23
+ --patch-nodes-file tmp/flow_patch_nodes.json \
24
+ --publish \
25
+ > tmp/flow_patch_apply.json
10
26
  ```
11
27
 
12
28
  ### 解读响应
@@ -14,6 +30,7 @@ qingflow builder flow apply \
14
30
  - `status: success` → 进入验证
15
31
  - `status: failed` → 查看 `error_code` / `message` / `blocking_issues`,修正后重试
16
32
  - `missing_input_node_ids` 警告(新建时常见)→ 可忽略,是正常现象
33
+ - 成功写入应读取 `write_executed=true`、`write_succeeded=true`、`safe_to_retry=false`;不要因中间读回 pending 立刻重放。
17
34
 
18
35
  ## 5.2 验证部署结果
19
36
 
@@ -37,7 +54,7 @@ qingflow --json builder flow get --app-key <APP_KEY> > tmp/deployed_flow.json
37
54
 
38
55
  若验证发现不一致:
39
56
  1. 分析差异原因(条件格式错误、节点缺失、边遗漏等)
40
- 2. 修正 `tmp/flow_spec.json`
57
+ 2. 修正 `tmp/flow_nodes.json` / `tmp/flow_transitions.json`;raw spec 高级路径才修正 `tmp/flow_spec.json`
41
58
  3. 重新验证 → apply → 对比
42
59
  4. **最多循环 3 次**;若 3 次后仍有不可修复的差异,告知用户并列出:
43
60
  - 已成功配置的部分
@@ -48,7 +48,7 @@
48
48
  | 在范围内 | 超出范围 |
49
49
  |----------|----------|
50
50
  | 基于已有应用搭建工作流 | 从零创建应用 |
51
- | 声明式 WorkflowSpec 生成与 apply | 操作复杂命令拼接 |
51
+ | public nodes/transitions 生成与 apply;必要时 raw WorkflowSpec | 操作复杂命令拼接 |
52
52
  | 分支条件(gateway + autoJudges)配置 | 后端不支持的高级特性 |
53
53
  | 审批/填写/抄送/自动化节点配置 | 修改字段定义 |
54
54
  | 成员/角色搜索用于节点负责人 | 组织架构管理 |
@@ -2137,7 +2137,7 @@ class PortalComponentPositionPatch(StrictModel):
2137
2137
 
2138
2138
 
2139
2139
  class PortalChartRefPatch(StrictModel):
2140
- app_key: str
2140
+ app_key: str | None = None
2141
2141
  chart_id: str | None = None
2142
2142
  chart_name: str | None = None
2143
2143
 
@@ -2145,6 +2145,8 @@ class PortalChartRefPatch(StrictModel):
2145
2145
  def validate_target(self) -> "PortalChartRefPatch":
2146
2146
  if not (self.chart_id or self.chart_name):
2147
2147
  raise ValueError("chart_ref requires chart_id or chart_name")
2148
+ if self.chart_name and not self.chart_id and not self.app_key:
2149
+ raise ValueError("chart_ref.app_key is required when resolving by chart_name")
2148
2150
  return self
2149
2151
 
2150
2152
 
@@ -486,6 +486,9 @@ class AiBuilderFacade:
486
486
  "verified": verified,
487
487
  "app_key": app_key,
488
488
  "current_version_id": apply_result.get("currentVersionId"),
489
+ "write_executed": True,
490
+ "write_succeeded": True,
491
+ "safe_to_retry": False,
489
492
  }
490
493
  return finalize(self._append_publish_result(profile=profile, app_key=app_key, publish=publish, response=response))
491
494
 
@@ -17345,6 +17348,8 @@ def _resolve_chart_reference(*, charts: QingbiReportTools, profile: str, ref: An
17345
17348
  app_key = str(getattr(ref, "app_key", "") or "").strip()
17346
17349
  chart_id = str(getattr(ref, "chart_id", "") or "").strip()
17347
17350
  chart_name = str(getattr(ref, "chart_name", "") or "").strip()
17351
+ if chart_id and not app_key:
17352
+ return {"chart_id": chart_id, "chart_name": chart_name, "app_key": None, "chart_type": ""}
17348
17353
  items = charts.qingbi_report_list(profile=profile, app_key=app_key).get("items") or []
17349
17354
  if chart_id:
17350
17355
  for item in items: