@josephyan/qingflow-cli 1.0.11 → 1.1.2

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.
Files changed (67) hide show
  1. package/README.md +3 -3
  2. package/npm/bin/qingflow.mjs +40 -2
  3. package/npm/lib/runtime.mjs +386 -15
  4. package/npm/scripts/postinstall.mjs +7 -2
  5. package/package.json +1 -1
  6. package/pyproject.toml +1 -1
  7. package/skills/qingflow-cli/SKILL.md +440 -0
  8. package/skills/qingflow-cli/manifest.yaml +10 -0
  9. package/skills/qingflow-cli/reference/QINGFLOW_CLI_ADMIN_CHEATSHEET.md +94 -0
  10. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md +485 -0
  11. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md +237 -0
  12. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_MATCH_RULES.md +137 -0
  13. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_PORTAL_WORKFLOW.md +263 -0
  14. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md +304 -0
  15. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_WORKSPACE_ICONS.md +41 -0
  16. package/skills/qingflow-cli/reference/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md +139 -0
  17. package/skills/qingflow-cli/reference/QINGFLOW_CLI_EXPLORATION_REPORT.md +84 -0
  18. package/skills/qingflow-cli/reference/QINGFLOW_CLI_FIELD_DATA_TYPES.md +129 -0
  19. package/skills/qingflow-cli/reference/QINGFLOW_CLI_MEMBER_CHEATSHEET.md +195 -0
  20. package/skills/qingflow-cli/reference/QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md +159 -0
  21. package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md +20 -0
  22. package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_IMPORT_WORKFLOW.md +176 -0
  23. package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md +163 -0
  24. package/skills/qingflow-cli/reference/QINGFLOW_CLI_SCHEMA_APPLY_FIELD_TYPES_AND_SCENARIOS.md +107 -0
  25. package/skills/qingflow-cli/reference/QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md +151 -0
  26. package/skills/qingflow-cli/reference/_batch_schema_complex.json +18 -0
  27. package/skills/qingflow-cli/reference/_batch_schema_scalar.json +17 -0
  28. package/skills/qingflow-cli/reference/charts_remove.example.json +1 -0
  29. package/skills/qingflow-cli/reference/charts_reorder.example.json +1 -0
  30. package/skills/qingflow-cli/reference/charts_upsert_bar.example.json +8 -0
  31. package/skills/qingflow-cli/reference/charts_upsert_dashboard_starter.example.json +37 -0
  32. package/skills/qingflow-cli/reference/charts_upsert_minimal.example.json +13 -0
  33. package/skills/qingflow-cli/reference/portal_sections_all_types.example.json +131 -0
  34. package/skills/qingflow-cli/reference/portal_sections_five_types.example.json +126 -0
  35. package/skills/qingflow-cli/reference/portal_sections_standard_workbench.example.json +128 -0
  36. package/skills/qingflow-cli/reference/schema_add_fields_minimal.example.json +7 -0
  37. package/skills/qingflow-cli/reference/schema_apply_add_fields_all_types.json +78 -0
  38. package/skills/qingflow-cli/reference/views_upsert_table_minimal.example.json +7 -0
  39. package/skills/qingflow-cli/scripts/builder-package-from-app-list.py +140 -0
  40. package/skills/qingflow-cli/scripts/find-app-by-keyword.py +132 -0
  41. package/skills/qingflow-cli/scripts/validate_qingflow_output_files.py +87 -0
  42. package/src/qingflow_mcp/__init__.py +1 -1
  43. package/src/qingflow_mcp/builder_facade/models.py +532 -48
  44. package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
  45. package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
  46. package/src/qingflow_mcp/cli/commands/app.py +3 -16
  47. package/src/qingflow_mcp/cli/commands/builder.py +354 -56
  48. package/src/qingflow_mcp/cli/commands/record.py +89 -2
  49. package/src/qingflow_mcp/cli/formatters.py +32 -1
  50. package/src/qingflow_mcp/cli/main.py +245 -3
  51. package/src/qingflow_mcp/public_surface.py +11 -8
  52. package/src/qingflow_mcp/response_trim.py +143 -14
  53. package/src/qingflow_mcp/server.py +15 -12
  54. package/src/qingflow_mcp/server_app_builder.py +108 -30
  55. package/src/qingflow_mcp/server_app_user.py +17 -18
  56. package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
  57. package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
  58. package/src/qingflow_mcp/solution/executor.py +3 -133
  59. package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
  60. package/src/qingflow_mcp/tools/app_tools.py +53 -8
  61. package/src/qingflow_mcp/tools/package_tools.py +16 -2
  62. package/src/qingflow_mcp/tools/record_tools.py +2095 -176
  63. package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
  64. package/src/qingflow_mcp/tools/solution_tools.py +30 -2
  65. package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
  66. package/src/qingflow_mcp/version.py +110 -0
  67. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
@@ -0,0 +1 @@
1
+ ["CHART_ID_FIRST", "CHART_ID_SECOND"]
@@ -0,0 +1,8 @@
1
+ [
2
+ {
3
+ "name": "示例柱状图",
4
+ "chart_type": "bar",
5
+ "group_by": ["REPLACE_WITH_DIMENSION_FIELD_NAME"],
6
+ "metric": "sum(REPLACE_WITH_NUMERIC_FIELD_NAME)"
7
+ }
8
+ ]
@@ -0,0 +1,37 @@
1
+ [
2
+ {
3
+ "name": "数据总量",
4
+ "chart_type": "target",
5
+ "metric": "count(*)",
6
+ "visibility": {
7
+ "mode": "workspace",
8
+ "selectors": {},
9
+ "external_mode": "not",
10
+ "external_selectors": {}
11
+ }
12
+ },
13
+ {
14
+ "name": "按状态分布",
15
+ "chart_type": "bar",
16
+ "group_by": ["REPLACE_WITH_STATUS_FIELD_NAME"],
17
+ "metric": "count(*)",
18
+ "visibility": {
19
+ "mode": "workspace",
20
+ "selectors": {},
21
+ "external_mode": "not",
22
+ "external_selectors": {}
23
+ }
24
+ },
25
+ {
26
+ "name": "按时间趋势",
27
+ "chart_type": "line",
28
+ "group_by": ["REPLACE_WITH_DATE_FIELD_NAME"],
29
+ "metric": "count(*)",
30
+ "visibility": {
31
+ "mode": "workspace",
32
+ "selectors": {},
33
+ "external_mode": "not",
34
+ "external_selectors": {}
35
+ }
36
+ }
37
+ ]
@@ -0,0 +1,13 @@
1
+ [
2
+ {
3
+ "name": "数据总量",
4
+ "chart_type": "target",
5
+ "metric": "count(*)",
6
+ "visibility": {
7
+ "mode": "workspace",
8
+ "selectors": {},
9
+ "external_mode": "not",
10
+ "external_selectors": {}
11
+ }
12
+ }
13
+ ]
@@ -0,0 +1,131 @@
1
+ [
2
+ {
3
+ "title": "筛选条_实验项_勿默认交付",
4
+ "source_type": "filter",
5
+ "position": {
6
+ "pc": {
7
+ "x": 0,
8
+ "y": 0,
9
+ "cols": 24,
10
+ "rows": 2
11
+ },
12
+ "mobile": {
13
+ "x": 0,
14
+ "y": 0,
15
+ "cols": 6,
16
+ "rows": 2
17
+ }
18
+ },
19
+ "config": {
20
+ "filterConfig": [],
21
+ "graphList": [
22
+ {
23
+ "graphType": "CHART",
24
+ "graphKey": "REPLACE_WITH_QINGBI_CHART_ID",
25
+ "graphName": "可选_图表显示名"
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ {
31
+ "title": "九宫格",
32
+ "source_type": "grid",
33
+ "position": {
34
+ "pc": {
35
+ "x": 0,
36
+ "y": 2,
37
+ "cols": 24,
38
+ "rows": 4
39
+ },
40
+ "mobile": {
41
+ "x": 0,
42
+ "y": 2,
43
+ "cols": 6,
44
+ "rows": 4
45
+ }
46
+ },
47
+ "config": {}
48
+ },
49
+ {
50
+ "title": "说明文字块",
51
+ "source_type": "text",
52
+ "position": {
53
+ "pc": {
54
+ "x": 0,
55
+ "y": 6,
56
+ "cols": 24,
57
+ "rows": 2
58
+ },
59
+ "mobile": {
60
+ "x": 0,
61
+ "y": 6,
62
+ "cols": 6,
63
+ "rows": 2
64
+ }
65
+ },
66
+ "text": "本文件仅用于排障/实验:filter 在当前 CLI 直写中可能不落库;稳定自动化模板请使用 portal_sections_five_types.example.json。"
67
+ },
68
+ {
69
+ "title": "外部链接",
70
+ "source_type": "link",
71
+ "position": {
72
+ "pc": {
73
+ "x": 0,
74
+ "y": 8,
75
+ "cols": 12,
76
+ "rows": 2
77
+ },
78
+ "mobile": {
79
+ "x": 0,
80
+ "y": 8,
81
+ "cols": 6,
82
+ "rows": 2
83
+ }
84
+ },
85
+ "url": "https://example.com"
86
+ },
87
+ {
88
+ "title": "应用视图块",
89
+ "source_type": "view",
90
+ "position": {
91
+ "pc": {
92
+ "x": 0,
93
+ "y": 10,
94
+ "cols": 24,
95
+ "rows": 8
96
+ },
97
+ "mobile": {
98
+ "x": 0,
99
+ "y": 10,
100
+ "cols": 6,
101
+ "rows": 8
102
+ }
103
+ },
104
+ "view_ref": {
105
+ "app_key": "YOUR_APP_KEY",
106
+ "view_key": "YOUR_VIEW_KEY"
107
+ }
108
+ },
109
+ {
110
+ "title": "指标图",
111
+ "source_type": "chart",
112
+ "position": {
113
+ "pc": {
114
+ "x": 0,
115
+ "y": 18,
116
+ "cols": 12,
117
+ "rows": 6
118
+ },
119
+ "mobile": {
120
+ "x": 0,
121
+ "y": 18,
122
+ "cols": 6,
123
+ "rows": 6
124
+ }
125
+ },
126
+ "chart_ref": {
127
+ "app_key": "YOUR_APP_KEY",
128
+ "chart_id": "YOUR_CHART_ID"
129
+ }
130
+ }
131
+ ]
@@ -0,0 +1,126 @@
1
+ [
2
+ {
3
+ "title": "门户说明",
4
+ "source_type": "text",
5
+ "position": {
6
+ "pc": {
7
+ "x": 0,
8
+ "y": 0,
9
+ "cols": 24,
10
+ "rows": 2
11
+ },
12
+ "mobile": {
13
+ "x": 0,
14
+ "y": 0,
15
+ "cols": 6,
16
+ "rows": 2
17
+ }
18
+ },
19
+ "text": "建议将门户设计成工作台:上方放入口,中部放指标,下方放待处理和异常列表。此文件仅演示 grid / text / link / view / chart 的稳定写法。"
20
+ },
21
+ {
22
+ "title": "业务入口",
23
+ "source_type": "grid",
24
+ "position": {
25
+ "pc": {
26
+ "x": 0,
27
+ "y": 2,
28
+ "cols": 24,
29
+ "rows": 4
30
+ },
31
+ "mobile": {
32
+ "x": 0,
33
+ "y": 2,
34
+ "cols": 6,
35
+ "rows": 4
36
+ }
37
+ },
38
+ "config": {
39
+ "gridTitle": "业务入口",
40
+ "beingShowTitle": true,
41
+ "items": [
42
+ {
43
+ "type": 1,
44
+ "jumpMode": 1,
45
+ "linkAppKey": "APP_KEY_MAIN",
46
+ "linkFormType": 1,
47
+ "title": "核心业务",
48
+ "customTitle": "核心业务",
49
+ "beingCustomTitle": false
50
+ },
51
+ {
52
+ "type": 1,
53
+ "jumpMode": 1,
54
+ "linkAppKey": "APP_KEY_TASK",
55
+ "linkFormType": 1,
56
+ "title": "待处理业务",
57
+ "customTitle": "待处理业务",
58
+ "beingCustomTitle": false
59
+ }
60
+ ]
61
+ }
62
+ },
63
+ {
64
+ "title": "核心指标",
65
+ "source_type": "chart",
66
+ "position": {
67
+ "pc": {
68
+ "x": 0,
69
+ "y": 6,
70
+ "cols": 8,
71
+ "rows": 6
72
+ },
73
+ "mobile": {
74
+ "x": 0,
75
+ "y": 6,
76
+ "cols": 6,
77
+ "rows": 6
78
+ }
79
+ },
80
+ "chart_ref": {
81
+ "app_key": "ead8ims5i401",
82
+ "chart_id": "mcp_fb104267c5c249ca"
83
+ }
84
+ },
85
+ {
86
+ "title": "待处理列表",
87
+ "source_type": "view",
88
+ "position": {
89
+ "pc": {
90
+ "x": 0,
91
+ "y": 12,
92
+ "cols": 12,
93
+ "rows": 8
94
+ },
95
+ "mobile": {
96
+ "x": 0,
97
+ "y": 12,
98
+ "cols": 6,
99
+ "rows": 8
100
+ }
101
+ },
102
+ "view_ref": {
103
+ "app_key": "ead8ims5i401",
104
+ "view_key": "ead8kbf1i402"
105
+ }
106
+ },
107
+ {
108
+ "title": "帮助文档",
109
+ "source_type": "link",
110
+ "position": {
111
+ "pc": {
112
+ "x": 12,
113
+ "y": 12,
114
+ "cols": 12,
115
+ "rows": 2
116
+ },
117
+ "mobile": {
118
+ "x": 0,
119
+ "y": 20,
120
+ "cols": 6,
121
+ "rows": 2
122
+ }
123
+ },
124
+ "url": "https://example.com"
125
+ }
126
+ ]
@@ -0,0 +1,128 @@
1
+ [
2
+ {
3
+ "title": "业务入口",
4
+ "source_type": "grid",
5
+ "position": {
6
+ "pc": {"x": 0, "y": 0, "cols": 24, "rows": 4},
7
+ "mobile": {"x": 0, "y": 0, "cols": 6, "rows": 4}
8
+ },
9
+ "config": {
10
+ "gridTitle": "业务入口",
11
+ "beingShowTitle": true,
12
+ "items": [
13
+ {
14
+ "type": 1,
15
+ "jumpMode": 1,
16
+ "linkAppKey": "APP_KEY_DEVICE",
17
+ "linkFormType": 1,
18
+ "title": "设备台账",
19
+ "customTitle": "设备台账",
20
+ "beingCustomTitle": false
21
+ },
22
+ {
23
+ "type": 1,
24
+ "jumpMode": 1,
25
+ "linkAppKey": "APP_KEY_REPAIR",
26
+ "linkFormType": 1,
27
+ "title": "故障报修",
28
+ "customTitle": "故障报修",
29
+ "beingCustomTitle": false
30
+ },
31
+ {
32
+ "type": 1,
33
+ "jumpMode": 1,
34
+ "linkAppKey": "APP_KEY_MAINTENANCE",
35
+ "linkFormType": 1,
36
+ "title": "保养管理",
37
+ "customTitle": "保养管理",
38
+ "beingCustomTitle": false
39
+ }
40
+ ]
41
+ }
42
+ },
43
+ {
44
+ "title": "设备总数",
45
+ "source_type": "chart",
46
+ "role": "metric",
47
+ "position": {
48
+ "pc": {"x": 0, "y": 4, "cols": 6, "rows": 5},
49
+ "mobile": {"x": 0, "y": 4, "cols": 6, "rows": 5}
50
+ },
51
+ "chart_ref": {"app_key": "APP_KEY_DEVICE", "chart_id": "CHART_ID_TOTAL"}
52
+ },
53
+ {
54
+ "title": "正常设备",
55
+ "source_type": "chart",
56
+ "role": "metric",
57
+ "position": {
58
+ "pc": {"x": 6, "y": 4, "cols": 6, "rows": 5},
59
+ "mobile": {"x": 0, "y": 9, "cols": 6, "rows": 5}
60
+ },
61
+ "chart_ref": {"app_key": "APP_KEY_DEVICE", "chart_id": "CHART_ID_NORMAL"}
62
+ },
63
+ {
64
+ "title": "维修中设备",
65
+ "source_type": "chart",
66
+ "role": "metric",
67
+ "position": {
68
+ "pc": {"x": 12, "y": 4, "cols": 6, "rows": 5},
69
+ "mobile": {"x": 0, "y": 14, "cols": 6, "rows": 5}
70
+ },
71
+ "chart_ref": {"app_key": "APP_KEY_DEVICE", "chart_id": "CHART_ID_REPAIRING"}
72
+ },
73
+ {
74
+ "title": "本月报修",
75
+ "source_type": "chart",
76
+ "role": "metric",
77
+ "position": {
78
+ "pc": {"x": 18, "y": 4, "cols": 6, "rows": 5},
79
+ "mobile": {"x": 0, "y": 19, "cols": 6, "rows": 5}
80
+ },
81
+ "chart_ref": {"app_key": "APP_KEY_REPAIR", "chart_id": "CHART_ID_REPAIR_MONTH"}
82
+ },
83
+ {
84
+ "title": "设备状态分布",
85
+ "source_type": "chart",
86
+ "position": {
87
+ "pc": {"x": 0, "y": 9, "cols": 8, "rows": 7},
88
+ "mobile": {"x": 0, "y": 24, "cols": 6, "rows": 7}
89
+ },
90
+ "chart_ref": {"app_key": "APP_KEY_DEVICE", "chart_id": "CHART_ID_STATUS_DIST"}
91
+ },
92
+ {
93
+ "title": "故障类型分布",
94
+ "source_type": "chart",
95
+ "position": {
96
+ "pc": {"x": 8, "y": 9, "cols": 8, "rows": 7},
97
+ "mobile": {"x": 0, "y": 31, "cols": 6, "rows": 7}
98
+ },
99
+ "chart_ref": {"app_key": "APP_KEY_REPAIR", "chart_id": "CHART_ID_FAULT_DIST"}
100
+ },
101
+ {
102
+ "title": "维修完成趋势",
103
+ "source_type": "chart",
104
+ "position": {
105
+ "pc": {"x": 16, "y": 9, "cols": 8, "rows": 7},
106
+ "mobile": {"x": 0, "y": 38, "cols": 6, "rows": 7}
107
+ },
108
+ "chart_ref": {"app_key": "APP_KEY_REPAIR", "chart_id": "CHART_ID_REPAIR_TREND"}
109
+ },
110
+ {
111
+ "title": "异常设备",
112
+ "source_type": "view",
113
+ "position": {
114
+ "pc": {"x": 0, "y": 16, "cols": 12, "rows": 11},
115
+ "mobile": {"x": 0, "y": 45, "cols": 6, "rows": 11}
116
+ },
117
+ "view_ref": {"app_key": "APP_KEY_DEVICE", "view_key": "VIEW_KEY_ABNORMAL_DEVICES"}
118
+ },
119
+ {
120
+ "title": "待处理工单",
121
+ "source_type": "view",
122
+ "position": {
123
+ "pc": {"x": 12, "y": 16, "cols": 12, "rows": 11},
124
+ "mobile": {"x": 0, "y": 56, "cols": 6, "rows": 11}
125
+ },
126
+ "view_ref": {"app_key": "APP_KEY_REPAIR", "view_key": "VIEW_KEY_PENDING_WORK_ORDERS"}
127
+ }
128
+ ]
@@ -0,0 +1,7 @@
1
+ [
2
+ {
3
+ "name": "示例搭建_CLI单行",
4
+ "type": "text",
5
+ "as_data_title": true
6
+ }
7
+ ]
@@ -0,0 +1,78 @@
1
+ [
2
+ {
3
+ "name": "QFCLI_AT_text",
4
+ "type": "text",
5
+ "as_data_title": true,
6
+ "description": "【本文件用法】推荐一次成功:npx @qingflow-tech/qingflow-cli --profile default builder schema apply --package-id <你的包tag_id> --app-name \"新应用名\" --create-if-missing --no-publish --add-fields-file schema_apply_add_fields_all_types.json。内含19种搭建 type(另含远程查询/代码块所需辅助 text),且已在本字段标记 as_data_title。关联字段 target_app_key 默认为本仓库实测用的模板应用 ead8ims5i401(须含「单行文字」「多行文字」);其它租户请改成你方可读的目标应用 app_key。若用 --app-key 向已有应用追加:须无「关联」字段且字段名不重复;每应用仅允许一个 relation。"
7
+ },
8
+ {"name": "QFCLI_AT_long_text", "type": "long_text"},
9
+ {"name": "QFCLI_AT_number", "type": "number"},
10
+ {"name": "QFCLI_AT_amount", "type": "amount"},
11
+ {"name": "QFCLI_AT_date", "type": "date"},
12
+ {"name": "QFCLI_AT_datetime", "type": "datetime"},
13
+ {"name": "QFCLI_AT_member", "type": "member"},
14
+ {"name": "QFCLI_AT_department", "type": "department", "department_scope": {"mode": "all"}},
15
+ {"name": "QFCLI_AT_single_select", "type": "single_select", "options": ["A", "B"]},
16
+ {"name": "QFCLI_AT_multi_select", "type": "multi_select", "options": ["X", "Y"]},
17
+ {"name": "QFCLI_AT_phone", "type": "phone"},
18
+ {"name": "QFCLI_AT_email", "type": "email"},
19
+ {"name": "QFCLI_AT_address", "type": "address"},
20
+ {"name": "QFCLI_AT_attachment", "type": "attachment", "as_data_cover": true},
21
+ {"name": "QFCLI_AT_boolean", "type": "boolean"},
22
+ {"name": "QFCLI_AT_ql_kw", "type": "text"},
23
+ {"name": "QFCLI_AT_ql_v1", "type": "text"},
24
+ {"name": "QFCLI_AT_ql_v2", "type": "text"},
25
+ {"name": "QFCLI_AT_cb_in", "type": "text"},
26
+ {"name": "QFCLI_AT_cb_out", "type": "text"},
27
+ {
28
+ "name": "QFCLI_AT_sub",
29
+ "type": "subtable",
30
+ "subfields": [
31
+ {"name": "QFCLI_AT_sub_c1", "type": "text"},
32
+ {"name": "QFCLI_AT_sub_c2", "type": "number"}
33
+ ]
34
+ },
35
+ {
36
+ "name": "QFCLI_AT_q_linker",
37
+ "type": "q_linker",
38
+ "q_linker_binding": {
39
+ "inputs": [{"field": {"name": "QFCLI_AT_ql_kw"}, "key": "k", "source": "query_param"}],
40
+ "request": {
41
+ "url": "https://httpbin.org/get",
42
+ "method": "GET",
43
+ "headers": [],
44
+ "query_params": [],
45
+ "body_type": 1,
46
+ "url_encoded_value": [],
47
+ "result_type": 1,
48
+ "auto_trigger": false,
49
+ "custom_button_text_enabled": true,
50
+ "custom_button_text": "查"
51
+ },
52
+ "outputs": [
53
+ {"alias": "a", "path": "$.headers.Host", "target_field": {"name": "QFCLI_AT_ql_v1"}},
54
+ {"alias": "b", "path": "$.url", "target_field": {"name": "QFCLI_AT_ql_v2"}}
55
+ ]
56
+ }
57
+ },
58
+ {
59
+ "name": "QFCLI_AT_code_block",
60
+ "type": "code_block",
61
+ "code_block_binding": {
62
+ "inputs": [{"field": {"name": "QFCLI_AT_cb_in"}, "var": "x"}],
63
+ "code": "qf_output = {}; qf_output.r = x ? '1' : '0';",
64
+ "auto_trigger": false,
65
+ "custom_button_text_enabled": true,
66
+ "custom_button_text": "运行",
67
+ "outputs": [{"alias": "r", "path": "$.r", "target_field": {"name": "QFCLI_AT_cb_out"}}]
68
+ }
69
+ },
70
+ {
71
+ "name": "QFCLI_AT_relation",
72
+ "type": "relation",
73
+ "target_app_key": "ead8ims5i401",
74
+ "relation_mode": "single",
75
+ "display_field": {"name": "单行文字"},
76
+ "visible_fields": [{"name": "多行文字"}]
77
+ }
78
+ ]
@@ -0,0 +1,7 @@
1
+ [
2
+ {
3
+ "name": "示例表视图_CLI模板",
4
+ "type": "table",
5
+ "columns": ["单行文字", "多行文字"]
6
+ }
7
+ ]
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env python3
2
+ """纯 CLI 曲线:在 **无** `package_list` / `package_resolve` 子命令时,用 `app list` + `builder app resolve` 解析包。
3
+
4
+ - `app list`(`GET /tag/apps` 扁平结果)常见含 **`package_name`**(分组显示名),**不一定**含数值 **`tag_id`**。
5
+ - `builder app resolve --app-key` 的 JSON 里常有 **`package_ids`**(与 MCP `package_get` 所用的 `tag_id` 同源)。
6
+
7
+ 子命令:
8
+ list-names 打印去重后的 `package_name` 列表(JSON 数组)
9
+ resolve-id <显示名> **精确匹配** `package_name`,取该组下第一个 `app_key`,再 `builder app resolve`,打印含 `package_ids` 的 JSON object
10
+
11
+ 环境(可选): `QINGFLOW_PROFILE` → 等价于 `qingflow --profile <名称>`
12
+
13
+ 注意:
14
+ - 若工作区内存在 **同名分组**(多个 `tag_id` 共用显示名),本脚本 **无法**区分,请用管理端或 MCP `package_list`。
15
+ - 某包下 **尚未有任何可见应用** 时,无法从 `app list` 曲线解析。
16
+
17
+ 用法:
18
+ ./scripts/builder-package-from-app-list.py list-names
19
+ ./scripts/builder-package-from-app-list.py resolve-id 'test'
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import os
26
+ import shutil
27
+ import subprocess
28
+ import sys
29
+ from typing import Any
30
+
31
+
32
+ def _qf_base() -> list[str]:
33
+ cmd = ["qingflow"]
34
+ pf = os.environ.get("QINGFLOW_PROFILE") or os.environ.get("QING_FLOW_PROFILE")
35
+ if pf:
36
+ cmd.extend(["--profile", pf])
37
+ return cmd
38
+
39
+
40
+ def _run_json(cmd: list[str]) -> dict[str, Any]:
41
+ proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=None)
42
+ if proc.returncode != 0:
43
+ sys.stdout.buffer.write(proc.stdout)
44
+ sys.stdout.flush()
45
+ raise SystemExit(proc.returncode)
46
+ try:
47
+ text = proc.stdout.decode("utf-8")
48
+ payload = json.loads(text)
49
+ except (UnicodeDecodeError, json.JSONDecodeError) as e:
50
+ print(f"qingflow JSON 解析失败: {e}", file=sys.stderr)
51
+ sys.stdout.buffer.write(proc.stdout)
52
+ sys.stdout.flush()
53
+ raise SystemExit(1) from e
54
+ if not isinstance(payload, dict):
55
+ print("qingflow JSON 根不是 object", file=sys.stderr)
56
+ raise SystemExit(1)
57
+ return payload
58
+
59
+
60
+ def _app_list_items(payload: dict[str, Any]) -> list[dict[str, Any]]:
61
+ it = payload.get("items")
62
+ if isinstance(it, list):
63
+ return [x for x in it if isinstance(x, dict)]
64
+ nested = payload.get("data")
65
+ if isinstance(nested, dict):
66
+ it2 = nested.get("items")
67
+ if isinstance(it2, list):
68
+ return [x for x in it2 if isinstance(x, dict)]
69
+ return []
70
+
71
+
72
+ def cmd_list_names() -> None:
73
+ if not shutil.which("qingflow"):
74
+ print("qingflow: command not found", file=sys.stderr)
75
+ sys.exit(127)
76
+ payload = _run_json(_qf_base() + ["--json", "app", "list"])
77
+ rows = _app_list_items(payload)
78
+ names: set[str] = set()
79
+ for o in rows:
80
+ pn = o.get("package_name")
81
+ if isinstance(pn, str) and pn.strip():
82
+ names.add(pn.strip())
83
+ json.dump(sorted(names), sys.stdout, ensure_ascii=False, indent=2)
84
+ sys.stdout.write("\n")
85
+
86
+
87
+ def cmd_resolve_id(display_name: str) -> None:
88
+ if not shutil.which("qingflow"):
89
+ print("qingflow: command not found", file=sys.stderr)
90
+ sys.exit(127)
91
+ want = display_name.strip()
92
+ if not want:
93
+ print("显示名不能为空", file=sys.stderr)
94
+ sys.exit(2)
95
+
96
+ payload = _run_json(_qf_base() + ["--json", "app", "list"])
97
+ rows = _app_list_items(payload)
98
+ app_key: str | None = None
99
+ for o in rows:
100
+ pn = o.get("package_name")
101
+ if isinstance(pn, str) and pn.strip() == want:
102
+ ak = o.get("app_key")
103
+ if isinstance(ak, str) and ak.strip():
104
+ app_key = ak.strip()
105
+ break
106
+ if not app_key:
107
+ print(json.dumps({"error": "no_app_under_package_name", "package_name": want}, ensure_ascii=False, indent=2))
108
+ sys.exit(3)
109
+
110
+ resolved = _run_json(_qf_base() + ["--json", "builder", "app", "resolve", "--app-key", app_key])
111
+ out = {
112
+ "package_name": want,
113
+ "sample_app_key": app_key,
114
+ "package_ids": resolved.get("package_ids"),
115
+ "resolve": resolved,
116
+ }
117
+ json.dump(out, sys.stdout, ensure_ascii=False, indent=2)
118
+ sys.stdout.write("\n")
119
+
120
+
121
+ def main() -> None:
122
+ if len(sys.argv) < 2:
123
+ print(__doc__.strip(), file=sys.stderr)
124
+ sys.exit(2)
125
+ sub = sys.argv[1].strip().lower()
126
+ if sub in {"list-names", "list_names", "names"}:
127
+ cmd_list_names()
128
+ return
129
+ if sub in {"resolve-id", "resolve_id", "resolve"}:
130
+ if len(sys.argv) != 3:
131
+ print("用法: … resolve-id '<package显示名>'", file=sys.stderr)
132
+ sys.exit(2)
133
+ cmd_resolve_id(sys.argv[2])
134
+ return
135
+ print(__doc__.strip(), file=sys.stderr)
136
+ sys.exit(2)
137
+
138
+
139
+ if __name__ == "__main__":
140
+ main()