@josephyan/qingflow-app-user-mcp 1.1.22 → 1.1.24
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@1.1.
|
|
6
|
+
npm install @josephyan/qingflow-app-user-mcp@1.1.24
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-user-mcp@1.1.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-user-mcp@1.1.24 qingflow-app-user-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -24897,8 +24897,8 @@ def _build_form_payload_for_edit_fields(
|
|
|
24897
24897
|
parsed_section_id = _coerce_positive_int(section.get("section_id"))
|
|
24898
24898
|
if parsed_section_id is not None:
|
|
24899
24899
|
wrapper["sectionId"] = parsed_section_id
|
|
24900
|
-
elif template is None and
|
|
24901
|
-
wrapper
|
|
24900
|
+
elif template is None and _coerce_positive_int(wrapper.get("sectionId")) is None:
|
|
24901
|
+
wrapper.pop("sectionId", None)
|
|
24902
24902
|
wrapper["innerQuestions"] = inner_rows
|
|
24903
24903
|
form_rows.append([wrapper])
|
|
24904
24904
|
|
|
@@ -2259,6 +2259,7 @@ class AiBuilderTools(ToolBase):
|
|
|
2259
2259
|
app_shell_apply_ms = 0
|
|
2260
2260
|
relation_compile_ms = 0
|
|
2261
2261
|
app_field_apply_ms = 0
|
|
2262
|
+
relation_repair_ms = 0
|
|
2262
2263
|
inline_layout_fallback_ms = 0
|
|
2263
2264
|
child_schema_write_ms = 0
|
|
2264
2265
|
child_inline_layout_ms = 0
|
|
@@ -2307,6 +2308,7 @@ class AiBuilderTools(ToolBase):
|
|
|
2307
2308
|
relation_compile_ms=relation_compile_ms,
|
|
2308
2309
|
app_field_apply_ms=app_field_apply_ms,
|
|
2309
2310
|
app_schema_parallel_wall_ms=app_field_apply_ms,
|
|
2311
|
+
relation_repair_parallel_wall_ms=relation_repair_ms,
|
|
2310
2312
|
native_inline_layout_ms=child_inline_layout_ms,
|
|
2311
2313
|
inline_layout_fallback_ms=inline_layout_fallback_ms,
|
|
2312
2314
|
child_schema_write_ms=child_schema_write_ms,
|
|
@@ -2930,6 +2932,125 @@ class AiBuilderTools(ToolBase):
|
|
|
2930
2932
|
item if isinstance(item, dict) else _multi_app_item_failure(index, apps[index], "APP_ITEM_NOT_PROCESSED", "app item was not processed")
|
|
2931
2933
|
for index, item in enumerate(final_items_by_index)
|
|
2932
2934
|
]
|
|
2935
|
+
|
|
2936
|
+
def relation_repair_patches(item: JSONObject) -> list[JSONObject]:
|
|
2937
|
+
details = item.get("details") if isinstance(item.get("details"), dict) else {}
|
|
2938
|
+
repair_plan = details.get("relation_repair_plan") if isinstance(details.get("relation_repair_plan"), list) else []
|
|
2939
|
+
patches: list[JSONObject] = []
|
|
2940
|
+
for plan_item in repair_plan:
|
|
2941
|
+
if not isinstance(plan_item, dict):
|
|
2942
|
+
continue
|
|
2943
|
+
patch = plan_item.get("suggested_patch")
|
|
2944
|
+
if isinstance(patch, dict):
|
|
2945
|
+
patches.append(deepcopy(patch))
|
|
2946
|
+
return patches
|
|
2947
|
+
|
|
2948
|
+
relation_repair_jobs: list[JSONObject] = []
|
|
2949
|
+
for item in final_items:
|
|
2950
|
+
if item.get("status") != "partial_success":
|
|
2951
|
+
continue
|
|
2952
|
+
app_key = str(item.get("app_key") or "").strip()
|
|
2953
|
+
patches = relation_repair_patches(item)
|
|
2954
|
+
if app_key and patches:
|
|
2955
|
+
relation_repair_jobs.append({"item": item, "app_key": app_key, "patches": patches})
|
|
2956
|
+
|
|
2957
|
+
def run_relation_repair_job(job: JSONObject) -> JSONObject:
|
|
2958
|
+
app_key = str(job.get("app_key") or "")
|
|
2959
|
+
patches = list(job.get("patches") or [])
|
|
2960
|
+
repair_started_at = time.perf_counter()
|
|
2961
|
+
try:
|
|
2962
|
+
repair_result = self._app_schema_apply_once(
|
|
2963
|
+
profile=profile,
|
|
2964
|
+
app_key=app_key,
|
|
2965
|
+
package_id=None,
|
|
2966
|
+
app_name="",
|
|
2967
|
+
app_title="",
|
|
2968
|
+
icon="",
|
|
2969
|
+
color="",
|
|
2970
|
+
visibility=None,
|
|
2971
|
+
publish=publish,
|
|
2972
|
+
add_fields=[],
|
|
2973
|
+
update_fields=patches,
|
|
2974
|
+
remove_fields=[],
|
|
2975
|
+
inline_form_layout_sections=None,
|
|
2976
|
+
allow_inline_layout_fallback=False,
|
|
2977
|
+
)
|
|
2978
|
+
public_repair = _publicize_package_fields(repair_result)
|
|
2979
|
+
except Exception as error: # pragma: no cover - defensive guard for unexpected worker failures
|
|
2980
|
+
return {"job": job, "elapsed_ms": _elapsed_ms(repair_started_at), "exception": repr(error)}
|
|
2981
|
+
return {
|
|
2982
|
+
"job": job,
|
|
2983
|
+
"elapsed_ms": _elapsed_ms(repair_started_at),
|
|
2984
|
+
"public_repair": public_repair,
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
if relation_repair_jobs:
|
|
2988
|
+
repair_phase_started_at = time.perf_counter()
|
|
2989
|
+
repair_workers = worker_count(len(relation_repair_jobs))
|
|
2990
|
+
repair_outputs: list[JSONObject] = []
|
|
2991
|
+
with ThreadPoolExecutor(max_workers=repair_workers) as executor:
|
|
2992
|
+
futures = [executor.submit(run_relation_repair_job, job) for job in relation_repair_jobs]
|
|
2993
|
+
for future in as_completed(futures):
|
|
2994
|
+
repair_outputs.append(future.result())
|
|
2995
|
+
relation_repair_ms += _elapsed_ms(repair_phase_started_at)
|
|
2996
|
+
for output in repair_outputs:
|
|
2997
|
+
job = output.get("job") if isinstance(output.get("job"), dict) else {}
|
|
2998
|
+
original = job.get("item") if isinstance(job.get("item"), dict) else {}
|
|
2999
|
+
if not original:
|
|
3000
|
+
continue
|
|
3001
|
+
index = _coerce_nonnegative_int(original.get("index"))
|
|
3002
|
+
if index is None or index >= len(final_items):
|
|
3003
|
+
continue
|
|
3004
|
+
repaired_item = deepcopy(original)
|
|
3005
|
+
exception = output.get("exception")
|
|
3006
|
+
if exception:
|
|
3007
|
+
repaired_item["relation_repair"] = {
|
|
3008
|
+
"attempted": True,
|
|
3009
|
+
"status": "failed",
|
|
3010
|
+
"error_code": "RELATION_REPAIR_EXCEPTION",
|
|
3011
|
+
"message": str(exception),
|
|
3012
|
+
}
|
|
3013
|
+
final_items[index] = repaired_item
|
|
3014
|
+
continue
|
|
3015
|
+
public_repair = output.get("public_repair") if isinstance(output.get("public_repair"), dict) else {}
|
|
3016
|
+
merge_child_duration(public_repair)
|
|
3017
|
+
if _schema_apply_result_has_write(public_repair):
|
|
3018
|
+
any_write_executed = True
|
|
3019
|
+
if _schema_apply_result_may_have_write(public_repair):
|
|
3020
|
+
any_write_may_have_succeeded = True
|
|
3021
|
+
repair_payload: JSONObject = {
|
|
3022
|
+
"attempted": True,
|
|
3023
|
+
"status": public_repair.get("status"),
|
|
3024
|
+
"error_code": public_repair.get("error_code"),
|
|
3025
|
+
"message": public_repair.get("message"),
|
|
3026
|
+
"verified": bool(public_repair.get("verified")),
|
|
3027
|
+
"field_diff": public_repair.get("field_diff") or {},
|
|
3028
|
+
**({"verification": public_repair.get("verification")} if isinstance(public_repair.get("verification"), dict) else {}),
|
|
3029
|
+
**({"details": public_repair.get("details")} if isinstance(public_repair.get("details"), dict) else {}),
|
|
3030
|
+
**({"duration_breakdown_ms": public_repair.get("duration_breakdown_ms")} if isinstance(public_repair.get("duration_breakdown_ms"), dict) else {}),
|
|
3031
|
+
}
|
|
3032
|
+
repaired_item["relation_repair"] = repair_payload
|
|
3033
|
+
repaired_item["field_diff"] = _merge_schema_field_diffs(repaired_item.get("field_diff") or {}, public_repair.get("field_diff") or {})
|
|
3034
|
+
repaired_item["field_diff_details"] = _merge_schema_field_diffs(
|
|
3035
|
+
repaired_item.get("field_diff_details") or {},
|
|
3036
|
+
public_repair.get("field_diff_details") or {},
|
|
3037
|
+
)
|
|
3038
|
+
if public_repair.get("status") == "success" and bool(public_repair.get("verified")):
|
|
3039
|
+
repaired_item["status"] = "success"
|
|
3040
|
+
repaired_item["error_code"] = None
|
|
3041
|
+
repaired_item["message"] = "applied schema patch; relation readback repaired"
|
|
3042
|
+
repaired_item["published"] = bool(public_repair.get("published"))
|
|
3043
|
+
repaired_item["verified"] = True
|
|
3044
|
+
original_verification = repaired_item.get("verification") if isinstance(repaired_item.get("verification"), dict) else {}
|
|
3045
|
+
repair_verification = public_repair.get("verification") if isinstance(public_repair.get("verification"), dict) else {}
|
|
3046
|
+
merged_verification = {**deepcopy(original_verification), **deepcopy(repair_verification)}
|
|
3047
|
+
repaired_item["verification"] = merged_verification
|
|
3048
|
+
details = repaired_item.get("details") if isinstance(repaired_item.get("details"), dict) else {}
|
|
3049
|
+
details = deepcopy(details)
|
|
3050
|
+
details.pop("relation_repair_plan", None)
|
|
3051
|
+
repaired_item["details"] = details
|
|
3052
|
+
final_items[index] = repaired_item
|
|
3053
|
+
|
|
2933
3054
|
pending_readback = sum(1 for item in final_items if item.get("status") == "pending_readback")
|
|
2934
3055
|
succeeded = sum(1 for item in final_items if item.get("status") in {"success", "partial_success"})
|
|
2935
3056
|
failed = sum(1 for item in final_items if item.get("status") == "failed")
|