@josephyan/qingflow-cli 1.1.4 → 1.1.6

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 (154) hide show
  1. package/README.md +7 -3
  2. package/docs/local-agent-install.md +57 -6
  3. package/entry_point.py +1 -1
  4. package/npm/bin/qingflow-skills.mjs +5 -0
  5. package/npm/bin/qingflow.mjs +1 -34
  6. package/npm/lib/runtime.mjs +21 -101
  7. package/npm/scripts/postinstall.mjs +1 -10
  8. package/package.json +3 -2
  9. package/pyproject.toml +1 -1
  10. package/skills/qingflow-cli/SKILL.md +58 -44
  11. package/skills/qingflow-cli/manifest.yaml +1 -1
  12. package/skills/qingflow-cli/reference/00-INDEX.md +35 -0
  13. package/skills/qingflow-cli/reference/builder/10-build-single-app.md +38 -0
  14. package/skills/qingflow-cli/reference/builder/20-build-complete-system.md +39 -0
  15. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_SCHEMA_APPLY_FIELD_TYPES_AND_SCENARIOS.md → builder/30-schema-fields.md} +52 -10
  16. package/skills/qingflow-cli/reference/builder/40-layout.md +52 -0
  17. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md → builder/50-views.md} +39 -15
  18. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md → builder/60-charts.md} +36 -13
  19. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_BUILDER_PORTAL_WORKFLOW.md → builder/70-portal.md} +36 -13
  20. package/skills/qingflow-cli/reference/builder/80-buttons-associated-resources.md +41 -0
  21. package/skills/qingflow-cli/reference/builder/90-workflow.md +34 -0
  22. package/skills/qingflow-cli/reference/builder/99-publish-verify.md +46 -0
  23. package/skills/qingflow-cli/reference/builder/README.md +41 -0
  24. package/skills/qingflow-cli/reference/builder/code-integrations/README.md +130 -0
  25. package/skills/qingflow-cli/reference/builder/code-integrations/code-block.md +66 -0
  26. package/skills/qingflow-cli/reference/builder/code-integrations/q-linker.md +77 -0
  27. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md → builder/reference/app-delivery-sop.md} +26 -16
  28. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/README.md +293 -0
  29. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/build-complete-system.md +809 -0
  30. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/build-single-app.md +830 -0
  31. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/complete-system-development-guide.md +123 -0
  32. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/create-app.md +182 -0
  33. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/environments.md +63 -0
  34. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/flow-actors-and-permissions.md +142 -0
  35. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/gotchas.md +108 -0
  36. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/match-rules.md +114 -0
  37. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/public-surface-sync.md +75 -0
  38. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/single-app-development-guide.md +58 -0
  39. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/solution-playbooks.md +52 -0
  40. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/tool-selection.md +107 -0
  41. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-flow.md +7 -0
  42. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-layout.md +7 -0
  43. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-schema.md +7 -0
  44. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-views.md +7 -0
  45. package/skills/qingflow-cli/reference/builder/workflow/01-overview.md +45 -0
  46. package/skills/qingflow-cli/reference/builder/workflow/02-update-mode.md +53 -0
  47. package/skills/qingflow-cli/reference/builder/workflow/03-flow-patterns.md +57 -0
  48. package/skills/qingflow-cli/reference/builder/workflow/04-stage1-business-modeling.md +131 -0
  49. package/skills/qingflow-cli/reference/builder/workflow/05-stage2-members-roles.md +29 -0
  50. package/skills/qingflow-cli/reference/builder/workflow/06-stage3-build-spec.md +165 -0
  51. package/skills/qingflow-cli/reference/builder/workflow/07-stage4-validate-spec.md +33 -0
  52. package/skills/qingflow-cli/reference/builder/workflow/08-stage5-apply-verify.md +51 -0
  53. package/skills/qingflow-cli/reference/builder/workflow/09-stage6-summary.md +88 -0
  54. package/skills/qingflow-cli/reference/builder/workflow/10-node-config-reference.md +93 -0
  55. package/skills/qingflow-cli/reference/builder/workflow/11-troubleshooting.md +15 -0
  56. package/skills/qingflow-cli/reference/builder/workflow/README.md +88 -0
  57. package/skills/qingflow-cli/reference/builder/workflow/workflow-schema.json +1754 -0
  58. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_ADMIN_CHEATSHEET.md → core/QINGFLOW_CLI_ADMIN_CHEATSHEET.md} +3 -3
  59. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md → core/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md} +6 -6
  60. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_EXPLORATION_REPORT.md → core/QINGFLOW_CLI_EXPLORATION_REPORT.md} +2 -2
  61. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_FIELD_DATA_TYPES.md → core/QINGFLOW_CLI_FIELD_DATA_TYPES.md} +11 -11
  62. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_MEMBER_CHEATSHEET.md → core/QINGFLOW_CLI_MEMBER_CHEATSHEET.md} +4 -4
  63. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md → core/QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md} +4 -4
  64. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md → record/QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md} +3 -3
  65. package/skills/qingflow-cli/reference/record/QINGFLOW_CLI_RECORD_DELETE_WORKFLOW.md +31 -0
  66. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_RECORD_IMPORT_WORKFLOW.md → record/QINGFLOW_CLI_RECORD_IMPORT_WORKFLOW.md} +4 -4
  67. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md → record/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md} +7 -7
  68. package/skills/qingflow-cli/reference/record/analysis/README.md +130 -0
  69. package/skills/qingflow-cli/reference/record/analysis/analysis-gotchas.md +91 -0
  70. package/skills/qingflow-cli/reference/record/analysis/analysis-patterns.md +112 -0
  71. package/skills/qingflow-cli/reference/record/analysis/business-context.md +74 -0
  72. package/skills/qingflow-cli/reference/record/analysis/confidence-reporting.md +69 -0
  73. package/skills/qingflow-cli/reference/record/analysis/data-access-playbook.md +106 -0
  74. package/skills/qingflow-cli/reference/record/analysis/pandas-recipes.md +172 -0
  75. package/skills/qingflow-cli/reference/record/analysis/report-format.md +76 -0
  76. package/skills/qingflow-cli/reference/record/insert/README.md +75 -0
  77. package/skills/qingflow-cli/reference/{QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md → task/QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md} +5 -5
  78. package/skills/qingflow-cli/reference/task/ops/README.md +131 -0
  79. package/skills/qingflow-cli/reference/task/ops/environments.md +43 -0
  80. package/skills/qingflow-cli/reference/task/ops/workflow-usage.md +26 -0
  81. package/skills/qingflow-cli/scripts/validate_system_build_summary.py +124 -0
  82. package/skills/qingflow-cli/scripts/workflow/diff_flow_spec.py +275 -0
  83. package/skills/qingflow-cli/scripts/workflow/validate_flow_spec.py +605 -0
  84. package/skills/qingflow-mcp-setup/SKILL.md +115 -0
  85. package/skills/qingflow-mcp-setup/agents/openai.yaml +4 -0
  86. package/skills/qingflow-mcp-setup/references/claude-desktop.md +34 -0
  87. package/skills/qingflow-mcp-setup/references/environments.md +62 -0
  88. package/skills/qingflow-mcp-setup/references/generic-stdio.md +32 -0
  89. package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +38 -0
  90. package/src/qingflow_mcp/__init__.py +1 -1
  91. package/src/qingflow_mcp/__main__.py +6 -2
  92. package/src/qingflow_mcp/builder_facade/models.py +282 -102
  93. package/src/qingflow_mcp/builder_facade/service.py +4192 -935
  94. package/src/qingflow_mcp/cli/commands/builder.py +316 -298
  95. package/src/qingflow_mcp/cli/commands/chart.py +1 -1
  96. package/src/qingflow_mcp/cli/commands/common.py +12 -3
  97. package/src/qingflow_mcp/cli/commands/exports.py +2 -2
  98. package/src/qingflow_mcp/cli/commands/imports.py +3 -3
  99. package/src/qingflow_mcp/cli/commands/portal.py +2 -2
  100. package/src/qingflow_mcp/cli/commands/record.py +101 -27
  101. package/src/qingflow_mcp/cli/commands/task.py +28 -47
  102. package/src/qingflow_mcp/cli/commands/view.py +1 -1
  103. package/src/qingflow_mcp/cli/context.py +0 -3
  104. package/src/qingflow_mcp/cli/formatters.py +784 -16
  105. package/src/qingflow_mcp/cli/main.py +117 -33
  106. package/src/qingflow_mcp/errors.py +43 -2
  107. package/src/qingflow_mcp/public_surface.py +26 -17
  108. package/src/qingflow_mcp/response_trim.py +81 -17
  109. package/src/qingflow_mcp/server.py +14 -12
  110. package/src/qingflow_mcp/server_app_builder.py +65 -21
  111. package/src/qingflow_mcp/server_app_user.py +22 -16
  112. package/src/qingflow_mcp/session_store.py +11 -7
  113. package/src/qingflow_mcp/solution/compiler/__init__.py +3 -1
  114. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  115. package/src/qingflow_mcp/solution/executor.py +245 -18
  116. package/src/qingflow_mcp/tools/ai_builder_tools.py +1780 -406
  117. package/src/qingflow_mcp/tools/app_tools.py +184 -43
  118. package/src/qingflow_mcp/tools/approval_tools.py +197 -35
  119. package/src/qingflow_mcp/tools/auth_tools.py +92 -16
  120. package/src/qingflow_mcp/tools/code_block_tools.py +298 -40
  121. package/src/qingflow_mcp/tools/custom_button_tools.py +64 -10
  122. package/src/qingflow_mcp/tools/directory_tools.py +236 -72
  123. package/src/qingflow_mcp/tools/export_tools.py +244 -34
  124. package/src/qingflow_mcp/tools/feedback_tools.py +9 -0
  125. package/src/qingflow_mcp/tools/file_tools.py +9 -3
  126. package/src/qingflow_mcp/tools/import_tools.py +336 -49
  127. package/src/qingflow_mcp/tools/navigation_tools.py +91 -12
  128. package/src/qingflow_mcp/tools/package_tools.py +118 -6
  129. package/src/qingflow_mcp/tools/portal_tools.py +39 -3
  130. package/src/qingflow_mcp/tools/qingbi_report_tools.py +116 -7
  131. package/src/qingflow_mcp/tools/record_tools.py +1141 -356
  132. package/src/qingflow_mcp/tools/resource_read_tools.py +188 -39
  133. package/src/qingflow_mcp/tools/role_tools.py +80 -9
  134. package/src/qingflow_mcp/tools/solution_tools.py +59 -45
  135. package/src/qingflow_mcp/tools/task_context_tools.py +662 -158
  136. package/src/qingflow_mcp/tools/task_tools.py +113 -29
  137. package/src/qingflow_mcp/tools/view_tools.py +106 -3
  138. package/src/qingflow_mcp/tools/workflow_tools.py +48 -4
  139. package/src/qingflow_mcp/tools/workspace_tools.py +71 -3
  140. /package/skills/qingflow-cli/reference/{QINGFLOW_CLI_BUILDER_MATCH_RULES.md → builder/reference/match-rules.md} +0 -0
  141. /package/skills/qingflow-cli/reference/{QINGFLOW_CLI_BUILDER_WORKSPACE_ICONS.md → builder/reference/workspace-icons.md} +0 -0
  142. /package/skills/qingflow-cli/reference/{charts_remove.example.json → examples/charts/charts_remove.example.json} +0 -0
  143. /package/skills/qingflow-cli/reference/{charts_reorder.example.json → examples/charts/charts_reorder.example.json} +0 -0
  144. /package/skills/qingflow-cli/reference/{charts_upsert_bar.example.json → examples/charts/charts_upsert_bar.example.json} +0 -0
  145. /package/skills/qingflow-cli/reference/{charts_upsert_dashboard_starter.example.json → examples/charts/charts_upsert_dashboard_starter.example.json} +0 -0
  146. /package/skills/qingflow-cli/reference/{charts_upsert_minimal.example.json → examples/charts/charts_upsert_minimal.example.json} +0 -0
  147. /package/skills/qingflow-cli/reference/{portal_sections_all_types.example.json → examples/portal/portal_sections_all_types.example.json} +0 -0
  148. /package/skills/qingflow-cli/reference/{portal_sections_five_types.example.json → examples/portal/portal_sections_five_types.example.json} +0 -0
  149. /package/skills/qingflow-cli/reference/{portal_sections_standard_workbench.example.json → examples/portal/portal_sections_standard_workbench.example.json} +0 -0
  150. /package/skills/qingflow-cli/reference/{_batch_schema_complex.json → examples/schema/_batch_schema_complex.json} +0 -0
  151. /package/skills/qingflow-cli/reference/{_batch_schema_scalar.json → examples/schema/_batch_schema_scalar.json} +0 -0
  152. /package/skills/qingflow-cli/reference/{schema_add_fields_minimal.example.json → examples/schema/schema_add_fields_minimal.example.json} +0 -0
  153. /package/skills/qingflow-cli/reference/{schema_apply_add_fields_all_types.json → examples/schema/schema_apply_add_fields_all_types.json} +0 -0
  154. /package/skills/qingflow-cli/reference/{views_upsert_table_minimal.example.json → examples/views/views_upsert_table_minimal.example.json} +0 -0
@@ -0,0 +1,112 @@
1
+ # Analysis Patterns
2
+
3
+ ## Canonical Sequence
4
+
5
+ 1. `app_get`
6
+ 2. `record_browse_schema_get`
7
+ 3. decide metric intent
8
+ 4. choose `record_access.columns / where / order_by`
9
+ 5. `record_access`
10
+ 6. Python over every returned CSV shard
11
+ 7. optional `record_list` or `record_get` only for sample/detail verification
12
+
13
+ Metric intent must be one of:
14
+
15
+ - `count`
16
+ - `sum`
17
+ - `avg`
18
+ - `distinct_count`
19
+ - ratio with numerator and denominator
20
+ - sorted ranking
21
+ - time trend
22
+ - period comparison
23
+
24
+ ## Distribution
25
+
26
+ 1. Fetch grouping field and filter fields.
27
+ 2. Run the field-quality profile for the grouping field.
28
+ 3. If the field passes quality gates, group by the readable field-id anchored column such as `项目状态__field_343283094`.
29
+ 4. Count rows and calculate share from the sum of counts.
30
+ 5. Report top groups plus total row count.
31
+
32
+ If the grouping field is ambiguous, ask the user to choose from a short candidate list.
33
+
34
+ ## Dimension Selection
35
+
36
+ When the user asks for a semantic bucket such as `板块`, `模块`, `业务线`, or `来源`, inspect candidate fields and choose the most reliable one:
37
+
38
+ 1. Match schema titles to the user's wording.
39
+ 2. Fetch candidate fields together if they are cheap.
40
+ 3. Profile `blank_rate`, period coverage, and distinct count.
41
+ 4. Prefer the candidate with clear semantics and usable coverage.
42
+ 5. If the literal field is sparse, downgrade it to `已填写样本观察` and use the nearest reliable fallback for the main conclusion.
43
+
44
+ Example: if `缺陷所属模块` is mostly empty but `缺陷所属平台` and `所属产品` are complete, use platform/product for the main conclusion and state that module-level analysis is limited.
45
+
46
+ Quality gates:
47
+
48
+ - Overall `blank_rate > 0.4`: not a primary conclusion dimension.
49
+ - Any compared period `blank_rate > 0.8`: not valid for period comparison.
50
+ - High-cardinality description/id fields are not dimensions unless the user explicitly asks for record-level ranking.
51
+
52
+ ## Ratio / Conversion / Penetration
53
+
54
+ 1. Define numerator and denominator in plain language.
55
+ 2. Fetch both populations with compatible scope.
56
+ 3. Compute ratio in Python.
57
+ 4. Report `numerator / denominator = percentage`.
58
+
59
+ If denominator is missing or scope differs, do not call the result a rate.
60
+
61
+ ## Average / Sum
62
+
63
+ 1. Fetch grouping field and numeric metric field.
64
+ 2. Convert the metric column with `pd.to_numeric(errors="coerce")`.
65
+ 3. Report count, sum, and average together when useful.
66
+ 4. State how blanks/non-numeric values were handled if material.
67
+
68
+ ## Ranking
69
+
70
+ 1. Build the metric in Python.
71
+ 2. Sort explicitly.
72
+ 3. Report Top N with metric values.
73
+ 4. Do not infer ranking from unsorted sample rows.
74
+
75
+ ## Trend
76
+
77
+ 1. Choose a date/time field from `suggested_time_fields`.
78
+ 2. Convert relative phrases into exact date ranges.
79
+ 3. Fetch the date field and metrics.
80
+ 4. Bucket in pandas by day/week/month/quarter/year.
81
+ 5. Report both absolute values and changes.
82
+
83
+ ## Same-Period Comparison
84
+
85
+ For `今年5月 vs 去年5月`:
86
+
87
+ 1. Use the same date field for both periods.
88
+ 2. Fetch the full combined date range or two separate compatible ranges.
89
+ 3. Apply identical business filters.
90
+ 4. Compute absolute delta and percentage delta.
91
+ 5. State both periods explicitly.
92
+
93
+ ## Sample Inspection
94
+
95
+ Use `record_list` only after the aggregate result is complete, and only for:
96
+
97
+ - representative examples
98
+ - checking surprising categories
99
+ - manually inspecting records behind a bucket
100
+
101
+ Never use `record_list` alone for final averages, shares, rankings, trends, or distributions.
102
+
103
+ ## Ambiguous Field Recovery
104
+
105
+ If the exact field is unclear:
106
+
107
+ 1. inspect `record_browse_schema_get.fields`
108
+ 2. use titles and suggested fields
109
+ 3. if one candidate is clearly dominant, proceed
110
+ 4. otherwise ask the user to confirm
111
+
112
+ Do not retry tools with guessed field names.
@@ -0,0 +1,74 @@
1
+ # Business Context
2
+
3
+ Use this when analysis depends on organization, aliases, ownership, stage semantics, or user-provided business definitions.
4
+
5
+ ## When To Check Context
6
+
7
+ Check for business context when the request mentions:
8
+
9
+ - department / team / group / region
10
+ - owner / assignee / sales rep / partner
11
+ - stage / status / funnel / conversion
12
+ - product line / business line
13
+ - same-period comparison
14
+ - "北斗部门", "SMB", "伙伴", or any named internal scope
15
+
16
+ ## Mapping Rules
17
+
18
+ Use explicit mappings in this order:
19
+
20
+ 1. the user's message in the current thread
21
+ 2. attached or local business context files
22
+ 3. schema-visible fields and sample records
23
+ 4. short clarification to the user
24
+
25
+ Do not infer hidden org hierarchy from memory. If the mapping changes the denominator or grouping, state it in the final answer.
26
+
27
+ Example:
28
+
29
+ ```python
30
+ dept_map = {
31
+ "烈焰组": "北斗部门",
32
+ "飓风组": "北斗部门",
33
+ }
34
+ df["部门口径"] = df["field_40"].replace(dept_map)
35
+ ```
36
+
37
+ Final wording:
38
+
39
+ ```text
40
+ 部门口径:将「烈焰组」「飓风组」合并计入「北斗部门」。
41
+ ```
42
+
43
+ ## Ratio Definitions
44
+
45
+ Before computing rates, define:
46
+
47
+ - numerator
48
+ - denominator
49
+ - time range
50
+ - grouping dimension
51
+ - exclusions
52
+
53
+ If any part is ambiguous, ask. Do not rename a count as a rate.
54
+
55
+ ## Time Scope
56
+
57
+ Normalize relative dates to exact dates before calling `record_access`.
58
+
59
+ Examples:
60
+
61
+ - `今年5月` -> `2026-05-01` to `2026-05-31` when current year is 2026
62
+ - `去年同期` -> same month range in the previous year
63
+ - `最近一个完整自然月` -> previous calendar month, not the last 30 days
64
+
65
+ ## Cross-App Reconciliation
66
+
67
+ If the analysis needs multiple apps:
68
+
69
+ 1. run the standard sequence per app
70
+ 2. keep each dataset's scope and completeness separately
71
+ 3. join in Python only on explicit ids or trusted business keys
72
+ 4. disclose join keys and unmatched records
73
+
74
+ If no reliable key exists, report the gap instead of forcing a join.
@@ -0,0 +1,69 @@
1
+ # Confidence Reporting
2
+
3
+ ## Full Conclusion Gate
4
+
5
+ Use `全量可信结论` only when:
6
+
7
+ - `record_browse_schema_get` was used
8
+ - data came from `record_access`
9
+ - all returned CSV shards were read in Python
10
+ - `record_access.complete=true`
11
+ - `record_access.truncated=false`
12
+ - `record_access.safe_for_final_conclusion=true`
13
+ - metric definitions are complete
14
+ - denominator exists for every ratio
15
+ - time fields and date ranges are explicit
16
+ - primary grouping dimensions pass field-quality gates
17
+
18
+ ## Initial Observation Gate
19
+
20
+ Use `初步观察` when:
21
+
22
+ - `record_access.status=needs_scope`
23
+ - `record_access.status=partial`
24
+ - `record_access.complete=false`
25
+ - `record_access.truncated=true`
26
+ - `record_access.safe_for_final_conclusion=false`
27
+ - evidence came from `record_list`
28
+ - scope or saved view filter is unverified
29
+
30
+ ## Anti-Mixing Rule
31
+
32
+ Do not combine full CSV-derived totals and sample-only rows in one sentence.
33
+
34
+ Correct split:
35
+
36
+ - full totals/distributions: `全量可信结论`
37
+ - illustrative examples: `样本观察`
38
+
39
+ ## Semantic Gate
40
+
41
+ Even with `safe_for_final_conclusion=true`, downgrade if:
42
+
43
+ - metric definition is incomplete
44
+ - denominator was not queried
45
+ - conclusion mentions trend but no time field was used
46
+ - conclusion mentions volume but no count was computed
47
+ - grouping depends on unconfirmed business aliases
48
+ - custom view scope is not verified
49
+ - primary grouping field has high missingness or poor period coverage
50
+
51
+ ## Partial Disclosure
52
+
53
+ If only part of the user request is complete:
54
+
55
+ - say which parts are complete
56
+ - say which parts are unresolved
57
+ - do not collapse into one all-clear conclusion
58
+
59
+ ## Compact Disclosure Template
60
+
61
+ ```text
62
+ 可信度:全量可信 / 初步观察
63
+ 数据完整性:complete=..., truncated=..., safe_for_final_conclusion=...
64
+ 字段质量:primary dimension blank_rate=..., period coverage=...
65
+ 取数字段:...
66
+ 时间范围:...
67
+ 业务口径:...
68
+ 限制:...
69
+ ```
@@ -0,0 +1,106 @@
1
+ # Data Access Playbook
2
+
3
+ This file is the operational state machine for `record_access`.
4
+
5
+ ## Required Sequence
6
+
7
+ 1. `app_get`
8
+ 2. choose `view_id` from `accessible_views`
9
+ 3. `record_browse_schema_get(app_key, view_id)`
10
+ 4. build `record_access.columns / where / order_by` from field ids
11
+ 5. run `record_access`
12
+ 6. read every CSV shard with Python
13
+
14
+ Do not call `record_access` with field titles, guessed ids, page controls, row limits, or profile.
15
+ CSV columns are readable and field-id anchored, for example `项目状态__field_343283094`; do not look for extra `schema.json` or README files.
16
+
17
+ ## Finding `record_access`
18
+
19
+ `record_access` can be available as an MCP tool or as a CLI subcommand. If the MCP surface does not show a top-level `record_access` tool, look under the Qingflow CLI record group before choosing any other path:
20
+
21
+ ```bash
22
+ qingflow record --help
23
+ qingflow record access --help
24
+ ```
25
+
26
+ The CLI call is:
27
+
28
+ ```bash
29
+ qingflow record access \
30
+ --app-key APP_KEY \
31
+ --view-id VIEW_ID \
32
+ --columns-file columns.json \
33
+ --where-file where.json \
34
+ --order-by-file order_by.json \
35
+ --json
36
+ ```
37
+
38
+ This is the same analysis path: it writes CSV shards and metadata for Python. Do not replace it with list browsing, export, QingBI, or aggregate helpers just because the MCP tool is not visible.
39
+
40
+ ## Request Patterns
41
+
42
+ ### Count or distribution
43
+
44
+ Fetch the grouping field and any time/business filter field.
45
+
46
+ ```json
47
+ {
48
+ "app_key": "APP_KEY",
49
+ "view_id": "system:all",
50
+ "columns": [{ "field_id": 18 }],
51
+ "where": [{ "field_id": 2, "op": "between", "value": ["2026-05-01", "2026-05-31"] }],
52
+ "order_by": []
53
+ }
54
+ ```
55
+
56
+ ### Trend
57
+
58
+ Fetch the date/time field plus metric fields.
59
+
60
+ ```json
61
+ {
62
+ "app_key": "APP_KEY",
63
+ "view_id": "system:all",
64
+ "columns": [{ "field_id": 2 }, { "field_id": 18 }],
65
+ "where": [{ "field_id": 2, "op": "between", "value": ["2026-01-01", "2026-12-31"] }],
66
+ "order_by": [{ "field_id": 2, "direction": "asc" }]
67
+ }
68
+ ```
69
+
70
+ ### Ratio
71
+
72
+ If numerator and denominator use different filters, run separate `record_access` calls. Only compute the ratio after both source datasets are complete and compatible.
73
+
74
+ ## Status Decisions
75
+
76
+ | Status | Meaning | Agent action |
77
+ |---|---|---|
78
+ | `success` + `safe_for_final_conclusion=true` | Full retrieved scope is reliable | Give final conclusion |
79
+ | `needs_scope` | Tool refused large unbounded scan, no CSV | Ask for scope or retry with explicit period/business filter |
80
+ | `partial` | Some CSV files written, but not full data | Give only subset observation |
81
+ | `complete=false` | Not all requested data is available | Do not present full-population conclusion |
82
+ | `truncated=true` | Tool had to stop before full scope | Disclose and narrow scope |
83
+
84
+ ## `needs_scope` Recovery
85
+
86
+ Use the returned `scope` object:
87
+
88
+ - `reported_total`: explain why scope is needed
89
+ - `suggested_time_fields`: choose likely date fields
90
+ - `recommended_where_examples`: reuse if they match the user request
91
+
92
+ If the user already provided a concrete month/quarter/year, retry with that period. If no business boundary is available, ask one short clarification.
93
+
94
+ ## `partial` Recovery
95
+
96
+ You may read the files, but must label output as partial:
97
+
98
+ - say which files/rows were analyzed
99
+ - do not use `全部`, `所有`, `整体`, or `全量`
100
+ - suggest narrowing time or business scope before final conclusion
101
+
102
+ ## View Scope
103
+
104
+ For custom views, the result is scoped to that saved view. If `verification.view_filter_verified=false`, disclose that the saved-filter scope could not be fully verified.
105
+
106
+ For board/gantt views, switch to a table-style view or `system:all` plus explicit filters.
@@ -0,0 +1,172 @@
1
+ # Pandas Recipes
2
+
3
+ Use Python to read returned CSV shards. Never paste raw CSV into the model context.
4
+
5
+ ## Load All Shards
6
+
7
+ ```python
8
+ import pandas as pd
9
+
10
+ files = [
11
+ "/absolute/path/records-0001.csv",
12
+ # include every record_access.files[].local_path
13
+ ]
14
+
15
+ frames = [pd.read_csv(path, dtype=str, keep_default_na=False) for path in files]
16
+ df = pd.concat(frames, ignore_index=True) if frames else pd.DataFrame()
17
+
18
+ # Columns are readable and field-id anchored, e.g. 项目状态__field_343283094.
19
+ fields = [] # optionally paste record_access.fields here if you need field-id metadata
20
+ field_by_id = {int(item["field_id"]): item for item in fields if "field_id" in item}
21
+ title_by_col = {item["column_name"]: item["title"] for item in fields if item.get("column_name")}
22
+ ```
23
+
24
+ ## Field Quality Profile
25
+
26
+ Run this before choosing final grouping dimensions.
27
+
28
+ ```python
29
+ def field_quality(frame: pd.DataFrame, *, date_col: str | None = None) -> pd.DataFrame:
30
+ rows = []
31
+ for col in frame.columns:
32
+ blank = frame[col].astype(str).eq("")
33
+ item = {
34
+ "column": col,
35
+ "row_count": len(frame),
36
+ "blank_count": int(blank.sum()),
37
+ "blank_rate": float(blank.mean()) if len(frame) else 0.0,
38
+ "distinct_count": int(frame[col].replace("", pd.NA).nunique(dropna=True)),
39
+ }
40
+ rows.append(item)
41
+ quality = pd.DataFrame(rows).sort_values(["blank_rate", "distinct_count"], ascending=[False, False])
42
+ if date_col and date_col in frame.columns:
43
+ tmp = frame.copy()
44
+ tmp["_period"] = pd.to_datetime(tmp[date_col], errors="coerce").dt.to_period("M").astype(str)
45
+ period_quality = []
46
+ for col in frame.columns:
47
+ if col == date_col:
48
+ continue
49
+ by_period = tmp.groupby("_period")[col].apply(lambda s: float(s.astype(str).eq("").mean()))
50
+ period_quality.append({"column": col, "max_period_blank_rate": float(by_period.max()) if len(by_period) else 0.0})
51
+ quality = quality.merge(pd.DataFrame(period_quality), on="column", how="left")
52
+ return quality
53
+ ```
54
+
55
+ Quality gates:
56
+
57
+ - `blank_rate > 0.4`: do not use as the primary conclusion dimension.
58
+ - `max_period_blank_rate > 0.8`: do not use for period comparison.
59
+ - Very high `distinct_count` fields are usually identifiers or descriptions, not grouping dimensions.
60
+ - High-missing dimensions may still be reported as `已填写样本观察`.
61
+
62
+ ## Column Selection
63
+
64
+ Prefer exact readable CSV columns. Use suffix matching only when you need to address a field id programmatically.
65
+
66
+ ```python
67
+ def col_by_field_id(frame, field_id: int) -> str:
68
+ suffix = f"__field_{field_id}"
69
+ matches = [col for col in frame.columns if col.endswith(suffix)]
70
+ if not matches:
71
+ raise KeyError(f"field_id not in CSV: {field_id}")
72
+ return matches[0]
73
+ ```
74
+
75
+ ## Count Distribution
76
+
77
+ ```python
78
+ col = "项目状态__field_18"
79
+ quality = field_quality(df)
80
+ blank_rate = quality.loc[quality["column"].eq(col), "blank_rate"].iloc[0]
81
+ if blank_rate > 0.4:
82
+ print(f"Use only as filled-sample observation: {col} blank_rate={blank_rate:.1%}")
83
+ dist = (
84
+ df[col]
85
+ .replace("", pd.NA)
86
+ .fillna("未填写")
87
+ .value_counts(dropna=False)
88
+ .rename_axis("group")
89
+ .reset_index(name="count")
90
+ )
91
+ dist["share"] = dist["count"] / dist["count"].sum()
92
+ ```
93
+
94
+ ## Numeric Aggregation
95
+
96
+ ```python
97
+ group_col = "项目状态__field_18"
98
+ amount_col = "金额__field_25"
99
+ tmp = df.copy()
100
+ tmp[amount_col] = (
101
+ tmp[amount_col]
102
+ .str.replace(",", "", regex=False)
103
+ .str.replace("¥", "", regex=False)
104
+ .pipe(pd.to_numeric, errors="coerce")
105
+ )
106
+ summary = (
107
+ tmp.groupby(group_col, dropna=False)[amount_col]
108
+ .agg(count="count", total="sum", avg="mean")
109
+ .reset_index()
110
+ .sort_values("total", ascending=False)
111
+ )
112
+ ```
113
+
114
+ ## Date Trend
115
+
116
+ ```python
117
+ date_col = "申请时间__field_2"
118
+ tmp = df.copy()
119
+ tmp[date_col] = pd.to_datetime(tmp[date_col], errors="coerce")
120
+ tmp = tmp.dropna(subset=[date_col])
121
+ tmp["month"] = tmp[date_col].dt.to_period("M").astype(str)
122
+ trend = tmp.groupby("month").size().reset_index(name="count")
123
+ ```
124
+
125
+ ## Year-Over-Year Month Comparison
126
+
127
+ ```python
128
+ date_col = "申请时间__field_2"
129
+ tmp = df.copy()
130
+ tmp[date_col] = pd.to_datetime(tmp[date_col], errors="coerce")
131
+ tmp = tmp.dropna(subset=[date_col])
132
+ tmp["year"] = tmp[date_col].dt.year
133
+ tmp["month"] = tmp[date_col].dt.month
134
+ monthly = tmp.groupby(["year", "month"]).size().reset_index(name="count")
135
+ ```
136
+
137
+ ## Ratio
138
+
139
+ ```python
140
+ numerator = len(df[df["项目状态__field_18"].eq("已成交")])
141
+ denominator = len(df)
142
+ ratio = numerator / denominator if denominator else None
143
+ ```
144
+
145
+ Always report numerator and denominator.
146
+
147
+ ## Multi-Select Cells
148
+
149
+ If values are serialized with delimiters, inspect samples first. For simple comma-separated values:
150
+
151
+ ```python
152
+ col = "标签__field_30"
153
+ exploded = (
154
+ df.assign(_value=df[col].str.split(","))
155
+ .explode("_value")
156
+ )
157
+ exploded["_value"] = exploded["_value"].str.strip()
158
+ multi_dist = exploded["_value"].value_counts().reset_index(name="count")
159
+ ```
160
+
161
+ ## Business Mapping
162
+
163
+ ```python
164
+ mapping = {
165
+ "烈焰组": "北斗部门",
166
+ "飓风组": "北斗部门",
167
+ }
168
+ department_col = "部门__field_40"
169
+ df["department_normalized"] = df[department_col].replace(mapping)
170
+ ```
171
+
172
+ State the mapping in the final answer.
@@ -0,0 +1,76 @@
1
+ # Report Format
2
+
3
+ Use this for user-facing analysis reports.
4
+
5
+ ## Short Answer
6
+
7
+ ```text
8
+ 结论:
9
+ - ...
10
+
11
+ 关键数据:
12
+ - 指标 A:...
13
+ - 指标 B:...
14
+
15
+ 口径与范围:
16
+ - 应用 / 视图:...
17
+ - 时间范围:...
18
+ - 字段:...
19
+ - 字段质量:...
20
+ - 业务映射:...
21
+ - 数据完整性:...
22
+
23
+ 限制:
24
+ - ...
25
+ ```
26
+
27
+ ## Detailed Report
28
+
29
+ ```text
30
+ 1. 分析范围
31
+ - app / view
32
+ - time range
33
+ - filters
34
+ - rows analyzed
35
+
36
+ 2. 核心结论
37
+ - concrete numbers first
38
+ - no vague adjectives without numbers
39
+
40
+ 3. 分项数据
41
+ - distribution / trend / ranking tables
42
+ - percentages with numerator and denominator
43
+
44
+ 4. 解释与建议
45
+ - separate facts from hypotheses
46
+
47
+ 5. 口径与可信度
48
+ - fields used
49
+ - field-quality gates and downgraded dimensions
50
+ - mapping rules
51
+ - completeness
52
+ - partial or unverified scope warnings
53
+ ```
54
+
55
+ ## Wording Rules
56
+
57
+ - Use `全量可信结论` only when the accessed scope is complete and safe.
58
+ - Use `初步观察` for partial or unverified data.
59
+ - Do not say `全部`, `所有`, `整体`, or `完整` when `safe_for_final_conclusion=false`.
60
+ - For ratios, always show `numerator / denominator`.
61
+ - For comparisons, show both periods' absolute values and the delta.
62
+
63
+ ## Comparison Template
64
+
65
+ ```text
66
+ 今年5月 vs 去年5月:
67
+ - 记录数:今年 X,去年 Y,变化 +Z(+P%)
68
+ - 金额:今年 X,去年 Y,变化 +Z(+P%)
69
+ - 结构变化:...
70
+
71
+ 口径:
72
+ - 时间字段:...
73
+ - 部门字段:...
74
+ - 部门映射:...
75
+ - 数据完整性:...
76
+ ```
@@ -0,0 +1,75 @@
1
+ # Qingflow CLI Record Insert
2
+
3
+ ## Default Path
4
+
5
+ `record schema insert -> record insert --items-file -> optional record get/readback`
6
+
7
+ Default to batch-shaped insert. A single new record is `items` with one row.
8
+
9
+ ## Core Tools
10
+
11
+ - `qingflow record schema insert`
12
+ - `qingflow record insert --items-file`
13
+ - `qingflow record member-candidates`
14
+ - `qingflow record department-candidates`
15
+ - file upload command when attachments are required
16
+
17
+ ## Working Rules
18
+
19
+ 1. Start with `record schema insert`
20
+ 2. Read `required_fields`, `optional_fields`, `runtime_linked_required_fields`, and `payload_template`
21
+ 3. Inside every field bucket, read field-level `linkage` first when present; it is the canonical static hint for linked visibility, reference-driven auto fill, or formula-driven fields
22
+ 4. Inside `optional_fields`, pay special attention to any field with `may_become_required=true`; these are writable fields that can become required when linked visibility or option-driven rules activate
23
+ 5. Build `items` as `[{"fields": {...}}]`, where each `fields` map uses field titles from the insert schema
24
+ 6. Treat `runtime_linked_required_fields` as required-but-not-directly-writable runtime/upstream dependencies, not as fields to hand-fill blindly
25
+ 7. For `linkage.kind=logic_visibility`, read `sources` as upstream trigger fields and treat `role=manual_input_after_activation` as "fill this only after the upstream condition is satisfied"
26
+ 8. For `linkage.kind=reference_fill`, prefer filling the source field first; treat target fields with `role=auto_fill_preferred` or `auto_fill_only` as reference-driven outputs rather than blind manual inputs
27
+ 9. For `linkage.kind=formula_fill`, treat the field as formula/default-auto-fill driven unless the user explicitly asks to override it and the field is still writable
28
+ 10. If insert succeeds and single-record detail/readback matters, prefer `record get`; use `record list` only for batch row-shaped normalized readback
29
+ 11. Keep subtable payloads under the parent field as a row array
30
+ 12. Member / department / relation fields may accept natural strings directly, such as `"张三"`, `"直销部"`, or `"海军军医大学"`; do not pre-query ids by default
31
+ 13. If the write returns `status="needs_confirmation"`, stop and surface the candidates
32
+ 14. Retry failed rows only with explicit ids / objects after the user confirms
33
+ 15. Keep `verify_write=true` for production inserts
34
+ 16. If post-write detail context matters, read `record get` fields, `media_assets.items[].local_path`, `file_assets.items[].local_path`, `file_assets.items[].extraction.text_path`, and `semantic_context`; `record get` follows the frontend storage cookie redirect path for Qingflow attachments, so prefer local paths over remote URLs and do not expect legacy `data.normalized_record`
35
+ 17. Treat nested schema shape as guidance, not a brittle contract; do not hard-code transient implementation details like optional nested `field_id` shape when composing inserts
36
+ 18. For `partial_success`, read `created_record_ids`, then repair only the failed `items[].row_number` using `failed_fields`; never retry the whole batch after any row has `write_executed=true`
37
+
38
+ ## Field Notes
39
+
40
+ - `searchable_fields` on relation fields defines the backend-native searchable columns
41
+ - `accepts_natural_input=true` means the field may accept a natural string before explicit id fallback
42
+ - `may_become_required=true` means the field is writable now, but may turn required after linked visibility or option rules activate
43
+ - `linkage.kind=logic_visibility` means the field is statically tied to linked visibility or option-driven rules
44
+ - `linkage.kind=reference_fill` means the field participates in reference-based auto fill or default matching logic
45
+ - `linkage.kind=formula_fill` means the field usually comes from formula/default auto-fill logic
46
+ - `linkage.sources` lists the upstream field titles that influence the current field
47
+ - `linkage.affects_fields` lists downstream field titles that may change when this field changes
48
+ - `linkage.role=auto_fill_only` means "normally do not hand-fill this unless the product explicitly requires it"
49
+ - `requires_upload=true` means upload the file first, then write the returned value
50
+ - `failed_fields[].next_action` tells the next repair step for that row
51
+
52
+ ## CLI Pattern
53
+
54
+ Use a JSON array file:
55
+
56
+ ```bash
57
+ qingflow record insert --app-key APP_KEY --items-file records.json --json
58
+ ```
59
+
60
+ `records.json`:
61
+
62
+ ```json
63
+ [
64
+ { "fields": { "客户名称": "测试客户", "负责人": "张三" } }
65
+ ]
66
+ ```
67
+
68
+ ## Do Not
69
+
70
+ - Do not skip `record schema insert`
71
+ - Do not invent missing required fields
72
+ - Do not flatten subtable leaf fields to the top level
73
+ - Do not pre-query or silently guess member / department / relation ids when a natural string is enough
74
+ - Do not retry a whole batch after `created_record_ids` is non-empty
75
+ - Do not bind logic to a transient nested schema serialization detail when the field title and parent table already identify the legal payload shape