@josephyan/qingflow-app-user-mcp 0.2.0-beta.94 → 0.2.0-beta.95

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-app-user-mcp@0.2.0-beta.94
6
+ npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.95
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.94 qingflow-app-user-mcp
12
+ npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.95 qingflow-app-user-mcp
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-app-user-mcp",
3
- "version": "0.2.0-beta.94",
3
+ "version": "0.2.0-beta.95",
4
4
  "description": "Operational end-user MCP for Qingflow records, tasks, comments, and directory workflows.",
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 = "0.2.0b94"
7
+ version = "0.2.0b95"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
 
6
6
  __all__ = ["__version__"]
7
7
 
8
- _FALLBACK_VERSION = "0.2.0b94"
8
+ _FALLBACK_VERSION = "0.2.0b95"
9
9
 
10
10
 
11
11
  def _resolve_local_pyproject_version() -> str | None:
@@ -1,12 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import base64
3
4
  from copy import deepcopy
4
5
  from dataclasses import dataclass, field
5
6
  import json
6
7
  import os
8
+ import random
7
9
  import re
10
+ import string
8
11
  import tempfile
9
12
  from typing import Any, cast
13
+ from urllib.parse import quote_plus, unquote_plus
10
14
  from uuid import uuid4
11
15
 
12
16
  from ..backend_client import BackendRequestContext
@@ -143,6 +147,7 @@ JUDGE_EQUAL_ANY = 9
143
147
  JUDGE_FUZZY_MATCH = 19
144
148
  JUDGE_INCLUDE_ANY = 20
145
149
  DEFAULT_TYPE_RELATION = 2
150
+ DEFAULT_TYPE_FORMULA = 3
146
151
  RELATION_TYPE_Q_LINKER = 2
147
152
  RELATION_TYPE_CODE_BLOCK = 3
148
153
 
@@ -12927,6 +12932,48 @@ def _copy_present_keys(
12927
12932
  return payload
12928
12933
 
12929
12934
 
12935
+ def _looks_like_backend_encoded_formula(value: str) -> bool:
12936
+ if len(value) <= 32:
12937
+ return False
12938
+ encoded = value[16:-16]
12939
+ if not encoded:
12940
+ return False
12941
+ try:
12942
+ decoded = base64.b64decode(encoded, validate=True).decode("utf-8")
12943
+ unquote_plus(decoded)
12944
+ except Exception:
12945
+ return False
12946
+ return True
12947
+
12948
+
12949
+ def _encode_formula_for_backend_save(value: Any) -> Any:
12950
+ if not isinstance(value, str) or not value:
12951
+ return value
12952
+ if _looks_like_backend_encoded_formula(value):
12953
+ return value
12954
+ encoded = quote_plus(value, encoding="utf-8")
12955
+ b64_value = base64.b64encode(encoded.encode("utf-8")).decode("ascii")
12956
+ alphabet = string.ascii_letters + string.digits
12957
+ prefix = "".join(random.choice(alphabet) for _ in range(16))
12958
+ suffix = "".join(random.choice(alphabet) for _ in range(16))
12959
+ return f"{prefix}{b64_value}{suffix}"
12960
+
12961
+
12962
+ def _normalize_formula_defaults_for_save(value: Any) -> None:
12963
+ if isinstance(value, list):
12964
+ for item in value:
12965
+ _normalize_formula_defaults_for_save(item)
12966
+ return
12967
+ if not isinstance(value, dict):
12968
+ return
12969
+ if _coerce_any_int(value.get("queDefaultType")) == DEFAULT_TYPE_FORMULA and value.get("queDefaultValue"):
12970
+ value["queDefaultValue"] = _encode_formula_for_backend_save(value.get("queDefaultValue"))
12971
+ for key in ("subQuestions", "innerQuestions"):
12972
+ nested = value.get(key)
12973
+ if isinstance(nested, (list, dict)):
12974
+ _normalize_formula_defaults_for_save(nested)
12975
+
12976
+
12930
12977
  def _normalize_reference_question_for_save(value: Any, *, ordinal: int) -> dict[str, Any] | None:
12931
12978
  if not isinstance(value, dict):
12932
12979
  return None
@@ -13090,6 +13137,8 @@ def _normalize_question_relations_for_save(question_relations: list[dict[str, An
13090
13137
  value = relation.get(key)
13091
13138
  if value is None:
13092
13139
  continue
13140
+ if key == "matchRuleFormula":
13141
+ value = _encode_formula_for_backend_save(value)
13093
13142
  item[key] = deepcopy(value)
13094
13143
  if item:
13095
13144
  normalized.append(item)
@@ -13412,6 +13461,7 @@ def _build_form_payload_from_fields(
13412
13461
  for row in form_rows:
13413
13462
  _apply_row_widths(row)
13414
13463
  payload = default_form_payload(title, form_rows)
13464
+ _normalize_formula_defaults_for_save(payload.get("formQues"))
13415
13465
  payload["editVersionNo"] = int(current_schema.get("editVersionNo") or 1)
13416
13466
  payload["questionRelations"] = _normalize_question_relations_for_save(
13417
13467
  question_relations if question_relations is not None else (current_schema.get("questionRelations") or [])
@@ -13529,6 +13579,7 @@ def _build_form_payload_for_edit_fields(
13529
13579
 
13530
13580
  payload = _build_form_save_base_payload(current_schema, title)
13531
13581
  payload["formQues"] = form_rows
13582
+ _normalize_formula_defaults_for_save(payload.get("formQues"))
13532
13583
  payload["questionRelations"] = normalized_relations
13533
13584
  payload["editVersionNo"] = int(current_schema.get("editVersionNo") or 1)
13534
13585
  return payload
@@ -14945,6 +14996,7 @@ def _build_form_payload_from_existing_schema(
14945
14996
 
14946
14997
  payload = _build_form_save_base_payload(current_schema, str(current_schema.get("formTitle") or "未命名应用"))
14947
14998
  payload["formQues"] = form_rows
14999
+ _normalize_formula_defaults_for_save(payload.get("formQues"))
14948
15000
  payload["questionRelations"] = _normalize_question_relations_for_save(current_schema.get("questionRelations") or [])
14949
15001
  payload["editVersionNo"] = int(current_schema.get("editVersionNo") or 1)
14950
15002
  payload.setdefault("formTitle", current_schema.get("formTitle") or "未命名应用")