@josephyan/qingflow-app-user-mcp 0.2.0-beta.80 → 0.2.0-beta.82
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.
|
|
6
|
+
npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.82
|
|
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.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.82 qingflow-app-user-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -542,7 +542,10 @@ class AiBuilderFacade:
|
|
|
542
542
|
"warnings": [],
|
|
543
543
|
"verification": {
|
|
544
544
|
"package_exists": True,
|
|
545
|
-
"visibility_verified":
|
|
545
|
+
"visibility_verified": _visibility_matches_expected(
|
|
546
|
+
verification.get("visibility"),
|
|
547
|
+
_public_visibility_from_member_auth(desired_auth),
|
|
548
|
+
),
|
|
546
549
|
},
|
|
547
550
|
"verified": True,
|
|
548
551
|
**{
|
|
@@ -3429,7 +3432,7 @@ class AiBuilderFacade:
|
|
|
3429
3432
|
response = ViewGetResponse(
|
|
3430
3433
|
view_key=view_key,
|
|
3431
3434
|
base_info=base_info,
|
|
3432
|
-
visibility=_public_visibility_from_member_auth(base_info.get("auth")),
|
|
3435
|
+
visibility=_public_visibility_from_member_auth(config.get("auth") or base_info.get("auth")),
|
|
3433
3436
|
config=deepcopy(config) if isinstance(config, dict) else {},
|
|
3434
3437
|
questions=questions,
|
|
3435
3438
|
associations=associations,
|
|
@@ -8688,6 +8691,50 @@ def _visibility_summary(visibility: dict[str, Any]) -> dict[str, Any]:
|
|
|
8688
8691
|
}
|
|
8689
8692
|
|
|
8690
8693
|
|
|
8694
|
+
def _visibility_matches_expected(actual: Any, expected: Any) -> bool:
|
|
8695
|
+
if not isinstance(actual, dict) or not isinstance(expected, dict):
|
|
8696
|
+
return False
|
|
8697
|
+
if str(actual.get("mode") or "") != str(expected.get("mode") or ""):
|
|
8698
|
+
return False
|
|
8699
|
+
if str(actual.get("external_mode") or "") != str(expected.get("external_mode") or ""):
|
|
8700
|
+
return False
|
|
8701
|
+
|
|
8702
|
+
actual_selectors = actual.get("selectors") if isinstance(actual.get("selectors"), dict) else {}
|
|
8703
|
+
expected_selectors = expected.get("selectors") if isinstance(expected.get("selectors"), dict) else {}
|
|
8704
|
+
actual_external = actual.get("external_selectors") if isinstance(actual.get("external_selectors"), dict) else {}
|
|
8705
|
+
expected_external = expected.get("external_selectors") if isinstance(expected.get("external_selectors"), dict) else {}
|
|
8706
|
+
|
|
8707
|
+
def sorted_values(source: dict[str, Any], key: str) -> list[str]:
|
|
8708
|
+
return sorted(str(item) for item in (source.get(key) or []) if item is not None and str(item).strip())
|
|
8709
|
+
|
|
8710
|
+
for key in ("member_uids", "dept_ids", "role_ids"):
|
|
8711
|
+
if sorted_values(actual_selectors, key) != sorted_values(expected_selectors, key):
|
|
8712
|
+
return False
|
|
8713
|
+
for key in ("member_ids", "dept_ids"):
|
|
8714
|
+
if sorted_values(actual_external, key) != sorted_values(expected_external, key):
|
|
8715
|
+
return False
|
|
8716
|
+
|
|
8717
|
+
# Backends commonly enrich id-based selectors with names/emails on readback; require
|
|
8718
|
+
# caller-specified text selectors only when no id selector anchors that subject.
|
|
8719
|
+
text_selector_pairs = (
|
|
8720
|
+
(actual_selectors, expected_selectors, "member_uids", "member_emails"),
|
|
8721
|
+
(actual_selectors, expected_selectors, "member_uids", "member_names"),
|
|
8722
|
+
(actual_selectors, expected_selectors, "dept_ids", "dept_names"),
|
|
8723
|
+
(actual_selectors, expected_selectors, "role_ids", "role_names"),
|
|
8724
|
+
(actual_external, expected_external, "member_ids", "member_emails"),
|
|
8725
|
+
)
|
|
8726
|
+
for actual_group, expected_group, id_key, text_key in text_selector_pairs:
|
|
8727
|
+
if sorted_values(expected_group, id_key):
|
|
8728
|
+
continue
|
|
8729
|
+
expected_text = sorted_values(expected_group, text_key)
|
|
8730
|
+
if expected_text and sorted_values(actual_group, text_key) != expected_text:
|
|
8731
|
+
return False
|
|
8732
|
+
|
|
8733
|
+
if "include_sub_departs" in expected_selectors and actual_selectors.get("include_sub_departs") != expected_selectors.get("include_sub_departs"):
|
|
8734
|
+
return False
|
|
8735
|
+
return True
|
|
8736
|
+
|
|
8737
|
+
|
|
8691
8738
|
def _mapping_contains(actual: Any, expected: Any) -> bool:
|
|
8692
8739
|
if isinstance(expected, dict):
|
|
8693
8740
|
if not isinstance(actual, dict):
|