@thinkingai/ae-cli 6.1.19 → 6.1.21

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 (370) hide show
  1. package/README.md +96 -38
  2. package/README.zh.md +96 -38
  3. package/dist/{auth-QPEVVBKT.js → auth-XZNXFRJS.js} +236 -127
  4. package/dist/{capability-ASI62I4A.js → capability-FYTU3X6L.js} +80 -37
  5. package/dist/{chunk-QL6R6TSK.js → chunk-4NRCTUZJ.js} +27045 -477
  6. package/dist/{chunk-JYMGHGCE.js → chunk-57RRFUEZ.js} +42 -15
  7. package/dist/chunk-6ZIQV5GW.js +26 -0
  8. package/dist/{chunk-KZ6ZHF5J.js → chunk-7FTTULED.js} +14 -14
  9. package/dist/chunk-7XGFSUOM.js +623 -0
  10. package/dist/chunk-CCS66K4K.js +155 -0
  11. package/dist/{chunk-B5HMQAOM.js → chunk-DVMLWQD4.js} +8 -186
  12. package/dist/{chunk-KEWVSO64.js → chunk-DX5CDO34.js} +28 -18
  13. package/dist/chunk-EQ255HKO.js +38248 -0
  14. package/dist/{chunk-6QK7SYYY.js → chunk-HBGADCKA.js} +29 -37
  15. package/dist/{chunk-GJXRF7Y6.js → chunk-HFGZGYCG.js} +54 -81
  16. package/dist/chunk-JOCDD4ON.js +15 -0
  17. package/dist/{chunk-TKHSULJT.js → chunk-KPQY44JQ.js} +6 -0
  18. package/dist/{chunk-FR2EDAQM.js → chunk-MAPZ7VB6.js} +90 -2
  19. package/dist/chunk-V2NUHPXF.js +196 -0
  20. package/dist/{chunk-S5PONFBM.js → chunk-VYXXOKYS.js} +9 -9
  21. package/dist/{community-report-client-6OL6GBQW.js → community-report-client-CU22W53K.js} +2 -4
  22. package/dist/{config-XNMACCKX.js → config-XO3LI3SA.js} +8 -9
  23. package/dist/context-IFJI3LIT.js +46 -0
  24. package/dist/{data-integration-4NZGZ45E.js → data-integration-HNGUKFIC.js} +55 -44
  25. package/dist/index.js +122 -112
  26. package/dist/{local-data-upload-client-EFHDLXFG.js → local-data-upload-client-GTRIT64F.js} +4 -5
  27. package/dist/{memory-HBJQ2GC5.js → memory-QGPSNCQS.js} +4 -6
  28. package/dist/{metadata-62EWBEIG.js → metadata-DI5BMYFU.js} +8 -10
  29. package/dist/{model-BHLJ2QMT.js → model-RNPQXIBI.js} +4 -6
  30. package/dist/{personal-semantic-preference-JBVMAI7L.js → personal-semantic-preference-5C3WUXFI.js} +11 -10
  31. package/dist/{project-semantic-BQ4MPUS5.js → project-semantic-3LF6Q6JZ.js} +29 -25
  32. package/dist/{sync-MUWPRM5I.js → sync-O45NXEQY.js} +7 -8
  33. package/dist/{te-agent-WQZTMEK4.js → te-agent-K5MSPNHJ.js} +393 -90
  34. package/dist/{te-analysis-MNCG65LU.js → te-analysis-AISWCOOZ.js} +1175 -377
  35. package/dist/{te-community-BNE6KREL.js → te-community-4OYU3BDA.js} +10 -33
  36. package/dist/{te-dataops-TXLKM2W6.js → te-dataops-NFIPB6FX.js} +19 -20
  37. package/dist/{te-engage-TPKLRVTL.js → te-engage-BAM3GBFX.js} +13 -15
  38. package/dist/{te-experiment-6BYKTCY7.js → te-experiment-GUTZXZ5Z.js} +132 -16
  39. package/dist/te-kb-3TS73NO6.js +1992 -0
  40. package/dist/{te-system-44LZJDTQ.js → te-system-STMHLS5J.js} +12 -9
  41. package/dist/{te-team-XMP47YXE.js → te-team-3I5AOX3N.js} +6 -8
  42. package/dist/{update-UODFOZ4P.js → update-RZXLPCRH.js} +7 -8
  43. package/package.json +29 -19
  44. package/skills/ae-agent/SKILL.md +30 -13
  45. package/skills/ae-agent/references/agent-distribution.md +94 -0
  46. package/skills/ae-agent/references/approval-request.md +4 -0
  47. package/skills/ae-agent/references/command_index.md +9 -2
  48. package/skills/ae-agent/references/create-automation.md +20 -2
  49. package/skills/ae-agent/references/get-agent-context.md +70 -0
  50. package/skills/ae-agent/references/list-automations.md +18 -3
  51. package/skills/ae-agent/references/list-mcp-credentials.md +1 -1
  52. package/skills/ae-agent/references/mcp-token.md +3 -3
  53. package/skills/ae-agent/references/set-mcp-credential.md +0 -1
  54. package/skills/ae-agent/references/update-automation.md +18 -0
  55. package/skills/ae-analysis/SKILL.md +101 -79
  56. package/skills/ae-analysis/references/adhoc_export.md +11 -18
  57. package/skills/ae-analysis/references/adhoc_run.md +17 -7
  58. package/skills/ae-analysis/references/agent_review_detail.md +11 -0
  59. package/skills/ae-analysis/references/agent_review_evidence.md +46 -0
  60. package/skills/ae-analysis/references/agent_review_list.md +9 -0
  61. package/skills/ae-analysis/references/agent_review_preflight.md +96 -0
  62. package/skills/ae-analysis/references/agent_review_priorities_comparisons.md +76 -0
  63. package/skills/ae-analysis/references/agent_review_records.md +9 -0
  64. package/skills/ae-analysis/references/agent_review_retry.md +12 -0
  65. package/skills/ae-analysis/references/agent_review_review.md +16 -0
  66. package/skills/ae-analysis/references/agent_review_submit_to_page.md +184 -0
  67. package/skills/ae-analysis/references/ai_models/attribution.md +29 -0
  68. package/skills/ae-analysis/references/ai_models/distribution.md +40 -0
  69. package/skills/ae-analysis/references/ai_models/event.md +108 -0
  70. package/skills/ae-analysis/references/ai_models/funnel.md +46 -0
  71. package/skills/ae-analysis/references/ai_models/heat_map.md +26 -0
  72. package/skills/ae-analysis/references/ai_models/interval.md +20 -0
  73. package/skills/ae-analysis/references/ai_models/path.md +38 -0
  74. package/skills/ae-analysis/references/ai_models/prop_analysis.md +39 -0
  75. package/skills/ae-analysis/references/ai_models/rank_list.md +25 -0
  76. package/skills/ae-analysis/references/ai_models/retention.md +70 -0
  77. package/skills/ae-analysis/references/ai_models/revenue.md +28 -0
  78. package/skills/ae-analysis/references/ai_models/sql.md +74 -0
  79. package/skills/ae-analysis/references/ai_models/tag.md +19 -0
  80. package/skills/ae-analysis/references/ai_models.md +32 -453
  81. package/skills/ae-analysis/references/alert_create.md +7 -7
  82. package/skills/ae-analysis/references/alert_delete.md +4 -6
  83. package/skills/ae-analysis/references/alert_detail_list.md +7 -9
  84. package/skills/ae-analysis/references/alert_get.md +5 -7
  85. package/skills/ae-analysis/references/alert_job_list.md +4 -6
  86. package/skills/ae-analysis/references/alert_list.md +6 -8
  87. package/skills/ae-analysis/references/alert_notice_config_list.md +4 -6
  88. package/skills/ae-analysis/references/alert_start.md +5 -7
  89. package/skills/ae-analysis/references/alert_stop.md +5 -7
  90. package/skills/ae-analysis/references/alert_update.md +8 -8
  91. package/skills/ae-analysis/references/analysis_data_export.md +72 -0
  92. package/skills/ae-analysis/references/analysis_data_retrieval.md +32 -196
  93. package/skills/ae-analysis/references/analysis_gateway_assets.md +23 -180
  94. package/skills/ae-analysis/references/analysis_interpretation.md +37 -17
  95. package/skills/ae-analysis/references/asset_abnormal_get.md +0 -1
  96. package/skills/ae-analysis/references/asset_abnormal_list.md +0 -1
  97. package/skills/ae-analysis/references/asset_authentication_export.md +4 -0
  98. package/skills/ae-analysis/references/asset_authentication_list.md +7 -1
  99. package/skills/ae-analysis/references/asset_authentication_update.md +5 -1
  100. package/skills/ae-analysis/references/asset_batch_dashboard_schedule_freeze.md +8 -6
  101. package/skills/ae-analysis/references/asset_batch_delete.md +6 -6
  102. package/skills/ae-analysis/references/asset_batch_disable_auto_backup.md +4 -5
  103. package/skills/ae-analysis/references/asset_batch_disable_auto_update.md +5 -6
  104. package/skills/ae-analysis/references/asset_batch_handover.md +4 -5
  105. package/skills/ae-analysis/references/asset_batch_info_export.md +4 -5
  106. package/skills/ae-analysis/references/asset_batch_sql_export.md +5 -6
  107. package/skills/ae-analysis/references/asset_dependency_list.md +4 -5
  108. package/skills/ae-analysis/references/asset_export.md +4 -5
  109. package/skills/ae-analysis/references/asset_impact_list.md +5 -9
  110. package/skills/ae-analysis/references/asset_lineage_get.md +5 -6
  111. package/skills/ae-analysis/references/asset_list.md +4 -5
  112. package/skills/ae-analysis/references/asset_query_history_list.md +4 -8
  113. package/skills/ae-analysis/references/asset_recent_list.md +0 -1
  114. package/skills/ae-analysis/references/asset_search.md +12 -9
  115. package/skills/ae-analysis/references/asset_url_get.md +3 -4
  116. package/skills/ae-analysis/references/bi_panel_copy.md +2 -2
  117. package/skills/ae-analysis/references/bi_panel_page_data_export.md +4 -12
  118. package/skills/ae-analysis/references/bi_panel_page_data_run.md +2 -0
  119. package/skills/ae-analysis/references/catalog_export.md +4 -17
  120. package/skills/ae-analysis/references/catalog_list.md +4 -4
  121. package/skills/ae-analysis/references/check_delete.md +5 -7
  122. package/skills/ae-analysis/references/check_export.md +11 -11
  123. package/skills/ae-analysis/references/check_get.md +8 -10
  124. package/skills/ae-analysis/references/check_list.md +4 -6
  125. package/skills/ae-analysis/references/check_retry.md +8 -10
  126. package/skills/ae-analysis/references/check_run.md +2 -4
  127. package/skills/ae-analysis/references/command_index.md +46 -28
  128. package/skills/ae-analysis/references/cross_source_config.md +84 -0
  129. package/skills/ae-analysis/references/dashboard_report_data_export.md +5 -13
  130. package/skills/ae-analysis/references/dashboard_report_data_run.md +1 -1
  131. package/skills/ae-analysis/references/dashboard_update.md +15 -4
  132. package/skills/ae-analysis/references/datatable_columns_get.md +0 -1
  133. package/skills/ae-analysis/references/datatable_influence_list.md +0 -1
  134. package/skills/ae-analysis/references/datatable_version_get.md +0 -1
  135. package/skills/ae-analysis/references/datatable_version_list.md +0 -1
  136. package/skills/ae-analysis/references/debug_device_add.md +1 -2
  137. package/skills/ae-analysis/references/drilldown_entities_export.md +3 -3
  138. package/skills/ae-analysis/references/drilldown_events_export.md +3 -2
  139. package/skills/ae-analysis/references/drilldown_user_events_export.md +2 -2
  140. package/skills/ae-analysis/references/entity_detail_export.md +3 -2
  141. package/skills/ae-analysis/references/entity_detail_run.md +1 -0
  142. package/skills/ae-analysis/references/event_blacklist_add.md +5 -7
  143. package/skills/ae-analysis/references/event_blacklist_list.md +4 -6
  144. package/skills/ae-analysis/references/event_blacklist_update.md +6 -8
  145. package/skills/ae-analysis/references/event_changelog_list.md +0 -1
  146. package/skills/ae-analysis/references/event_create.md +0 -1
  147. package/skills/ae-analysis/references/event_detail_export.md +3 -2
  148. package/skills/ae-analysis/references/event_detail_run.md +1 -0
  149. package/skills/ae-analysis/references/event_export.md +0 -1
  150. package/skills/ae-analysis/references/event_get.md +0 -1
  151. package/skills/ae-analysis/references/event_hide_update.md +0 -1
  152. package/skills/ae-analysis/references/event_influence_list.md +0 -1
  153. package/skills/ae-analysis/references/event_list.md +0 -1
  154. package/skills/ae-analysis/references/event_property_bundle_export.md +5 -14
  155. package/skills/ae-analysis/references/event_property_bundle_import.md +2 -6
  156. package/skills/ae-analysis/references/event_relation_update.md +0 -1
  157. package/skills/ae-analysis/references/event_update.md +0 -1
  158. package/skills/ae-analysis/references/exchange_config_update.md +0 -1
  159. package/skills/ae-analysis/references/exchange_rate_refresh.md +0 -1
  160. package/skills/ae-analysis/references/exchange_rule_list.md +0 -1
  161. package/skills/ae-analysis/references/exchange_rule_update.md +0 -1
  162. package/skills/ae-analysis/references/exchange_rule_validate.md +0 -1
  163. package/skills/ae-analysis/references/governance_recommendation_decisions.md +23 -0
  164. package/skills/ae-analysis/references/governance_recommendation_export.md +108 -0
  165. package/skills/ae-analysis/references/governance_recommendation_submit.md +41 -0
  166. package/skills/ae-analysis/references/history_tag_data_drilldown_export.md +4 -4
  167. package/skills/ae-analysis/references/history_tag_data_export.md +3 -3
  168. package/skills/ae-analysis/references/ingest_error_list.md +7 -9
  169. package/skills/ae-analysis/references/ingest_summary.md +6 -8
  170. package/skills/ae-analysis/references/live_data_export.md +10 -10
  171. package/skills/ae-analysis/references/live_data_list.md +7 -9
  172. package/skills/ae-analysis/references/metadata_resolution.md +78 -0
  173. package/skills/ae-analysis/references/metric_export.md +0 -1
  174. package/skills/ae-analysis/references/metric_get.md +0 -1
  175. package/skills/ae-analysis/references/metric_list.md +4 -5
  176. package/skills/ae-analysis/references/metric_update.md +0 -1
  177. package/skills/ae-analysis/references/operation_record_export.md +4 -5
  178. package/skills/ae-analysis/references/operation_record_list.md +4 -5
  179. package/skills/ae-analysis/references/personal_semantic_preference_list.md +18 -1
  180. package/skills/ae-analysis/references/plan_change_log_export.md +10 -10
  181. package/skills/ae-analysis/references/plan_change_log_list.md +4 -6
  182. package/skills/ae-analysis/references/plan_delete_items.md +2 -4
  183. package/skills/ae-analysis/references/plan_export.md +9 -9
  184. package/skills/ae-analysis/references/plan_generate.md +2 -4
  185. package/skills/ae-analysis/references/plan_get.md +4 -6
  186. package/skills/ae-analysis/references/plan_import_excel.md +6 -8
  187. package/skills/ae-analysis/references/plan_save_items.md +2 -4
  188. package/skills/ae-analysis/references/plan_sync_from_meta.md +4 -6
  189. package/skills/ae-analysis/references/project_access_detail_get.md +0 -1
  190. package/skills/ae-analysis/references/project_data_power_get.md +0 -1
  191. package/skills/ae-analysis/references/project_data_power_list.md +0 -1
  192. package/skills/ae-analysis/references/project_data_power_upsert.md +0 -1
  193. package/skills/ae-analysis/references/project_entity_create.md +0 -1
  194. package/skills/ae-analysis/references/project_entity_event_list.md +0 -1
  195. package/skills/ae-analysis/references/project_entity_get.md +0 -1
  196. package/skills/ae-analysis/references/project_entity_list.md +0 -1
  197. package/skills/ae-analysis/references/project_entity_update.md +0 -1
  198. package/skills/ae-analysis/references/project_function_list.md +0 -1
  199. package/skills/ae-analysis/references/project_info_get.md +0 -1
  200. package/skills/ae-analysis/references/project_info_list.md +0 -1
  201. package/skills/ae-analysis/references/project_info_update.md +0 -1
  202. package/skills/ae-analysis/references/project_mark_time_create.md +0 -1
  203. package/skills/ae-analysis/references/project_mark_time_list.md +0 -1
  204. package/skills/ae-analysis/references/project_mark_time_update.md +0 -1
  205. package/skills/ae-analysis/references/project_member_add.md +6 -5
  206. package/skills/ae-analysis/references/project_member_batch_update.md +0 -1
  207. package/skills/ae-analysis/references/project_member_candidate_list.md +4 -3
  208. package/skills/ae-analysis/references/project_member_handover_run.md +2 -3
  209. package/skills/ae-analysis/references/project_member_list.md +0 -1
  210. package/skills/ae-analysis/references/project_member_receiver_list.md +0 -1
  211. package/skills/ae-analysis/references/project_member_update.md +0 -1
  212. package/skills/ae-analysis/references/project_owner_update.md +0 -1
  213. package/skills/ae-analysis/references/project_permission_binding_list.md +0 -1
  214. package/skills/ae-analysis/references/project_role_function_list.md +0 -1
  215. package/skills/ae-analysis/references/project_role_get.md +0 -1
  216. package/skills/ae-analysis/references/project_role_list.md +0 -1
  217. package/skills/ae-analysis/references/project_role_upsert.md +32 -2
  218. package/skills/ae-analysis/references/project_role_user_list.md +0 -1
  219. package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +214 -0
  220. package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +93 -0
  221. package/skills/ae-analysis/references/project_timezone_get.md +0 -1
  222. package/skills/ae-analysis/references/project_timezone_overview.md +0 -1
  223. package/skills/ae-analysis/references/project_timezone_update.md +0 -1
  224. package/skills/ae-analysis/references/project_user_id_items_update.md +0 -1
  225. package/skills/ae-analysis/references/property_changelog_list.md +0 -1
  226. package/skills/ae-analysis/references/property_create.md +0 -1
  227. package/skills/ae-analysis/references/property_export.md +0 -1
  228. package/skills/ae-analysis/references/property_get.md +0 -1
  229. package/skills/ae-analysis/references/property_hide_update.md +0 -1
  230. package/skills/ae-analysis/references/property_influence_list.md +0 -1
  231. package/skills/ae-analysis/references/property_list.md +3 -4
  232. package/skills/ae-analysis/references/property_related_events.md +0 -1
  233. package/skills/ae-analysis/references/property_relation_update.md +0 -1
  234. package/skills/ae-analysis/references/property_update.md +0 -1
  235. package/skills/ae-analysis/references/report_create.md +4 -2
  236. package/skills/ae-analysis/references/report_data_export.md +11 -9
  237. package/skills/ae-analysis/references/report_data_run.md +14 -7
  238. package/skills/ae-analysis/references/report_get.md +5 -3
  239. package/skills/ae-analysis/references/report_list.md +2 -0
  240. package/skills/ae-analysis/references/report_update.md +5 -3
  241. package/skills/ae-analysis/references/rule_create.md +5 -6
  242. package/skills/ae-analysis/references/rule_delete.md +5 -5
  243. package/skills/ae-analysis/references/rule_list.md +3 -4
  244. package/skills/ae-analysis/references/rule_schema.md +3 -4
  245. package/skills/ae-analysis/references/rule_update.md +5 -6
  246. package/skills/ae-analysis/references/sdk_sample_generate.md +2 -4
  247. package/skills/ae-analysis/references/sql_table_columns.md +1 -1
  248. package/skills/ae-analysis/references/super_metadata_batch_create.md +1 -1
  249. package/skills/ae-analysis/references/super_metadata_batch_edit.md +1 -1
  250. package/skills/ae-analysis/references/system_member_add.md +1 -2
  251. package/skills/ae-analysis/references/system_member_status_update.md +1 -1
  252. package/skills/ae-analysis/references/system_ops_alert_contact_list.md +1 -1
  253. package/skills/ae-analysis/references/system_ops_alert_contact_test.md +0 -1
  254. package/skills/ae-analysis/references/system_query_monitor_overview.md +3 -3
  255. package/skills/ae-analysis/references/system_query_task_export.md +4 -14
  256. package/skills/ae-analysis/references/system_query_task_get.md +1 -1
  257. package/skills/ae-analysis/references/system_query_task_list.md +5 -6
  258. package/skills/ae-analysis/references/system_receiver_address_upsert.md +3 -3
  259. package/skills/ae-analysis/references/system_receiver_detection_get.md +1 -1
  260. package/skills/ae-analysis/references/system_third_party_login_disable.md +1 -1
  261. package/skills/ae-analysis/references/system_usage_trend_export.md +3 -12
  262. package/skills/ae-analysis/references/user_cluster_list.md +1 -1
  263. package/skills/ae-analysis/references/user_cluster_member_export.md +4 -4
  264. package/skills/ae-analysis/references/user_tag_create.md +23 -1
  265. package/skills/ae-analysis/references/user_tag_list.md +1 -1
  266. package/skills/ae-analysis/references/user_tag_member_export.md +4 -4
  267. package/skills/ae-analysis/references/user_tag_models.md +9 -1
  268. package/skills/ae-analysis/references/user_tag_update.md +14 -2
  269. package/skills/ae-analysis/references/virtual_event_create.md +10 -5
  270. package/skills/ae-analysis/references/virtual_event_get.md +0 -1
  271. package/skills/ae-analysis/references/virtual_property_create.md +0 -1
  272. package/skills/ae-analysis/references/virtual_property_sql_rule_update.md +0 -1
  273. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +1054 -0
  274. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +112 -0
  275. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +30 -0
  276. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +2735 -0
  277. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +376 -0
  278. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/plan-kb-source-sync.mjs +264 -0
  279. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/precompiled-source.mjs +49 -0
  280. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/upload-kb-sources-concurrently.mjs +200 -0
  281. package/skills/ae-analysis/scripts/read_results.py +197 -0
  282. package/skills/ae-analysis-global/SKILL.md +1 -1
  283. package/skills/ae-capability/SKILL.md +1 -1
  284. package/skills/ae-community/SKILL.md +1 -1
  285. package/skills/ae-current-context/SKILL.md +53 -0
  286. package/skills/ae-data-integration/SKILL.md +6 -4
  287. package/skills/ae-data-integration/references/dimension-routing.md +36 -0
  288. package/skills/ae-data-integration/references/lark-bitable-source.md +288 -0
  289. package/skills/ae-data-integration/references/lark-sheet-source.md +130 -0
  290. package/skills/ae-data-integration/references/local-analysis.md +2 -0
  291. package/skills/ae-data-integration/references/manual-export-source.md +83 -0
  292. package/skills/ae-data-integration/references/reuse.md +2 -0
  293. package/skills/ae-data-integration/references/sink-upload.md +32 -0
  294. package/skills/ae-data-integration/references/source-inspect.md +1 -1
  295. package/skills/ae-data-integration/references/tracking-plan.md +5 -2
  296. package/skills/ae-data-integration/references/transform.md +1 -1
  297. package/skills/ae-data-integration/references/ue-mapping.md +7 -4
  298. package/skills/ae-data-integration/references/ue-routing.md +17 -1
  299. package/skills/ae-data-integration-helper/SKILL.md +5 -5
  300. package/skills/ae-data-integration-helper/references/android_sdk_faq.md +3 -3
  301. package/skills/ae-data-integration-helper/references/c_sdk_faq.md +3 -3
  302. package/skills/ae-data-integration-helper/references/cocoscreator_sdk_faq.md +1 -1
  303. package/skills/ae-data-integration-helper/references/cpp_server_sdk_faq.md +3 -3
  304. package/skills/ae-data-integration-helper/references/ios_sdk_faq.md +1 -1
  305. package/skills/ae-data-integration-helper/references/java_sdk_faq.md +3 -3
  306. package/skills/ae-data-integration-helper/references/javascript_sdk_faq.md +1 -1
  307. package/skills/ae-data-integration-helper/references/logbus2_guide.md +1 -1
  308. package/skills/ae-data-integration-helper/references/logbus2_parser_plugin.md +2 -2
  309. package/skills/ae-data-integration-helper/references/minigame_sdk_faq.md +2 -2
  310. package/skills/ae-data-integration-helper/references/miniprogram_sdk_faq.md +1 -1
  311. package/skills/ae-data-integration-helper/references/python_sdk_faq.md +2 -2
  312. package/skills/ae-data-integration-helper/references/restful_api_notes.md +2 -2
  313. package/skills/ae-data-integration-helper/references/sdk_log_guide.md +3 -3
  314. package/skills/ae-data-integration-helper/references/sdk_usage_notes.md +11 -11
  315. package/skills/ae-data-integration-helper/references/unity_sdk_faq.md +1 -1
  316. package/skills/ae-dataops/SKILL.md +1 -1
  317. package/skills/ae-engage/SKILL.md +4 -3
  318. package/skills/ae-engage/references/build-task-save-guide.md +3 -0
  319. package/skills/ae-engage/references/flow-metric-update.md +115 -1
  320. package/skills/ae-engage/references/save-flow.md +3 -0
  321. package/skills/ae-engage/references/save-task.md +21 -0
  322. package/skills/ae-engage/references/task-metric-update.md +151 -0
  323. package/skills/ae-experiment/SKILL.md +14 -7
  324. package/skills/ae-experiment/references/save_submit_external_experiment.md +52 -0
  325. package/skills/ae-experiment-design/SKILL.md +3 -3
  326. package/skills/ae-experiment-design/references/platform-operations.md +1 -1
  327. package/skills/ae-experiment-insight/SKILL.md +2 -2
  328. package/skills/ae-experiment-insight/references/platform-operations.md +1 -1
  329. package/skills/ae-generate-tracking-code/SKILL.md +2 -1
  330. package/skills/ae-generate-tracking-code/references/client-sdk-insert.md +1 -1
  331. package/skills/ae-generate-tracking-code/references/datax-config.md +1 -1
  332. package/skills/ae-generate-tracking-code/references/logbus-config.md +1 -1
  333. package/skills/ae-generate-tracking-code/references/modes.md +1 -1
  334. package/skills/ae-generate-tracking-code/references/server-sdk-insert.md +5 -5
  335. package/skills/ae-generate-tracking-code/references/snippet-delivery.md +3 -3
  336. package/skills/ae-generate-tracking-plan/SKILL.md +27 -15
  337. package/skills/ae-generate-tracking-plan/references/business-dimension-mapping.md +1 -1
  338. package/skills/ae-generate-tracking-plan/references/te-api.md +1 -0
  339. package/skills/ae-generate-tracking-plan/references/xlsx-schema.md +3 -2
  340. package/skills/ae-kb/SKILL.md +147 -37
  341. package/skills/ae-kb/references/analysis-workflow.md +292 -0
  342. package/skills/ae-kb/references/query-workflow.md +59 -29
  343. package/skills/ae-kb/references/source-mutations.md +95 -0
  344. package/skills/ae-kb/references/versions.md +46 -0
  345. package/skills/ae-kb-discovery/SKILL.md +5 -1
  346. package/skills/ae-metadata/SKILL.md +1 -1
  347. package/skills/ae-migrate-tracking-code/SKILL.md +195 -0
  348. package/skills/ae-migrate-tracking-code/references/ae-preset-properties.md +76 -0
  349. package/skills/ae-migrate-tracking-code/references/ir.md +167 -0
  350. package/skills/ae-migrate-tracking-code/references/mapping-framework.md +112 -0
  351. package/skills/ae-migrate-tracking-code/references/providers/README.md +58 -0
  352. package/skills/ae-migrate-tracking-code/references/providers/amplitude.md +208 -0
  353. package/skills/ae-migrate-tracking-code/references/providers/firebase.md +160 -0
  354. package/skills/ae-migrate-tracking-code/references/providers/ga4.md +92 -0
  355. package/skills/ae-migrate-tracking-code/references/providers/mixpanel.md +150 -0
  356. package/skills/ae-migrate-tracking-code/references/providers/sensors-data.md +146 -0
  357. package/skills/ae-project-semantic/SKILL.md +1 -1
  358. package/skills/ae-system/SKILL.md +5 -5
  359. package/skills/ae-team/SKILL.md +2 -2
  360. package/skills/ae-use-agent/SKILL.md +42 -0
  361. package/skills/ae-use-agent/references/local-agent.md +114 -0
  362. package/dist/auth-UMJAA72O.js +0 -15
  363. package/dist/chunk-533JK3YX.js +0 -72
  364. package/dist/chunk-DKEXH6Q5.js +0 -72
  365. package/dist/chunk-O6K2ODUE.js +0 -318
  366. package/dist/chunk-RWXIXOZG.js +0 -326
  367. package/dist/client-N7NGZUNI.js +0 -204
  368. package/dist/te-kb-BUD6N3NI.js +0 -1222
  369. package/skills/ae-agent/references/auto-provision-mcp-credentials.md +0 -57
  370. package/skills/ae-analysis/metadata_resolution.md +0 -184
@@ -0,0 +1,288 @@
1
+ # Source — online document (Feishu Bitable)
2
+
3
+ ## When this branch applies
4
+
5
+ The input is a **URL**, not a local path. Feishu Bitable (多维表格 / Base) links (`/base/`), and
6
+ wiki links that resolve to a Bitable, route here instead of [source-inspect.md](source-inspect.md).
7
+ Feishu sheet links still route to [lark-sheet-source.md](lark-sheet-source.md); a `/wiki/` link can be
8
+ either, so resolve it first (Step 1) and branch on the resolved type. The pipeline is identical
9
+ after the table is snapshotted to a local JSONL: business identification, tracking plan,
10
+ transform, and sink all reuse the local-file flow unchanged.
11
+
12
+ Only **Feishu sheets** and **Feishu Bitable (多维表格)** are supported in this phase. Other online
13
+ documents (Tencent Docs, DingTalk, WPS, Google Sheets, Notion) have no CLI read path — route to
14
+ [manual-export-source.md](manual-export-source.md), which has the user export the data themselves
15
+ and then rejoins the local-file flow.
16
+
17
+ ## Safety rules (online-specific)
18
+
19
+ - The URL, its token, the snapshot file path, and every record value are sensitive. Never print
20
+ source values while inspecting; summarize types, ratios, counts, and fingerprints only.
21
+ - Pulling records to the local machine moves data across a trust boundary. Before downloading
22
+ anything, tell the user the table will be snapshotted to a local file, and get their
23
+ confirmation when the data is not their own.
24
+ - The snapshot is a point-in-time copy. State the export timestamp (and the base timezone the
25
+ API reports), and note that the import reflects the exported moment only — a table that may be
26
+ edited mid-run is imported as of the snapshot, not live.
27
+ - lark-cli (Feishu) and ae-cli (AE) are two separate credential domains. Read Feishu with
28
+ lark-cli; upload to AE with ae-cli. Never forward a token from one to the other, and never
29
+ send an AE access token or CLI token to any Feishu endpoint.
30
+
31
+ ## Step 0 — Environment self-check (before any pull)
32
+
33
+ The Feishu read path depends on `lark-cli`, a CLI separate from ae-cli. Check it up front so a
34
+ missing install or a missing login surfaces as an environment problem, not as a data problem
35
+ mid-pipeline.
36
+
37
+ 1. **Detect lark-cli.** Run `lark-cli --version`. If the command is not found, stop and tell the
38
+ user to install it (`npm i -g @larksuite/cli`). Do not attempt to install it yourself, and do
39
+ not fall back to another read path — a half-provisioned Feishu client produces worse failures
40
+ than a clear "not installed" stop.
41
+ 2. **Check the login.** Run
42
+ `LARKSUITE_CLI_NO_UPDATE_NOTIFIER=1 LARKSUITE_CLI_NO_SKILLS_NOTIFIER=1 lark-cli auth status --json --verify`.
43
+ Reading a Bitable in the user's cloud space needs the **user** identity (`--as user`); the bot
44
+ identity cannot see a user's drive documents. If the user identity is unavailable or
45
+ unverified, follow the lark-shared skill's split-flow: start
46
+ `lark-cli auth login --scope "<scope>" --no-wait --json`, show the QR code / link to the user,
47
+ and only after the user confirms run `lark-cli auth login --device-code <device_code>`.
48
+ Authorization requires the user's participation — never bypass or automate it. The Bitable
49
+ read path needs the scopes `base:table:read`, `base:record:read`, and `base:field:read`.
50
+ 3. **Handle permission errors when they occur.** If a pull returns `permission_violations`
51
+ (missing scopes) together with `console_url` and `hint`, route by identity:
52
+ - user identity → add the missing scope with
53
+ `lark-cli auth login --scope "<missing_scope>"` (incremental grant);
54
+ - bot identity → direct the user to open the scope in the developer console via the returned
55
+ `console_url`; never run `auth login` for a bot.
56
+ If the base itself is not accessible to the user's account — a resource-side permission
57
+ problem, not a scope problem — ask the user to confirm the link is correct and that their
58
+ Feishu account can open the base. Do not retry against a different base silently.
59
+
60
+ ## Step 1 — Resolve the URL and locate the table
61
+
62
+ 1. **Resolve the URL to a base token.** Primary (richer — returns the title and unwraps wiki
63
+ links):
64
+ ```bash
65
+ lark-cli drive +inspect --url "<url>" --as user
66
+ ```
67
+ returns `{ok, identity: "user", data: {token, title, type, url}}`. A Bitable resolves with
68
+ `type: "bitable"` and its base token in `token`. If `type` is not `bitable`, leave this branch
69
+ — a sheet routes to [lark-sheet-source.md](lark-sheet-source.md). Domain-native alternative, which also
70
+ accepts wiki and record-share links:
71
+ ```bash
72
+ lark-cli base +url-resolve --url "<url>" --as user
73
+ ```
74
+ returns `{ok, identity: "user", data: {base_token, resource_type: "bitable", input_type}}`.
75
+ 2. **List the tables.**
76
+ ```bash
77
+ lark-cli base +table-list --base-token <base_token>
78
+ ```
79
+ returns `{ok, data: {tables: [{id, name, records_count, rev}], total}}`. Never guess a table
80
+ id or name. Surface the table list to the user with each table's record count; a base with one
81
+ table proceeds with it, multiple tables ask the user to choose, mirroring `--data-set` on a
82
+ local workbook.
83
+
84
+ ## Step 2 — Snapshot to a local JSONL
85
+
86
+ The base domain has **no workbook-export command** (only per-record reads and an attachment
87
+ downloader), so the snapshot is a **JSONL** built by paginating `+record-list` and zipping each
88
+ page into per-record objects — not an XLSX. The snapshot directory convention matches the sheet
89
+ flow: `.ae-cli/data-integration/online/<fingerprint>/snapshot.jsonl`, where `<fingerprint>` is a
90
+ short, collision-resistant name derived from the base token plus a timestamp (e.g. first 8 chars
91
+ of `sha256("<base_token>-<YYYYMMDD-HHMMSS>")`). One online source gets one directory, so a
92
+ re-export never overwrites an unrelated source. Create the directory before writing.
93
+
94
+ 1. **Survey the fields** (type knowledge for the mapping step, and attachment detection):
95
+ ```bash
96
+ lark-cli base +field-list --base-token <base_token> --table-id <table_id>
97
+ ```
98
+ returns
99
+ `{ok, data: {fields: [{id, name, type, style?, options?, multiple?, default_value?}], total}}`.
100
+ `style` and `options` are display metadata (currency code, date format, choice list);
101
+ `multiple` distinguishes single- from multi-select. Field-list order is NOT the record-list
102
+ order — do not carry it across to the zip step.
103
+ 2. **Paginate the records.** Always pass `--format json` explicitly — `+record-list` defaults to
104
+ **markdown**, unlike `+table-list`/`+field-list` which already default to json:
105
+ ```bash
106
+ lark-cli base +record-list --base-token <base_token> --table-id <table_id> --format json
107
+ ```
108
+ The JSON envelope is **column-oriented**, not record-oriented:
109
+ ```json
110
+ {
111
+ "ok": true, "identity": "user",
112
+ "data": {
113
+ "data": [["<…>", "<…>", true, 129.5, ["<…>"], ["<…>"], "<ISO8601>", ["<…>"]],
114
+ "fields": ["<…>", "<…>", "<…>", "<…>", "<…>", "<…>", "<…>", "<…>"],
115
+ "field_id_list": ["<…>", "…"],
116
+ "field_type_list": ["<…>", "…"],
117
+ "record_id_list": ["<…>", "…"],
118
+ "has_more": true,
119
+ "query_context": { "field_scope": "all_fields", "record_scope": "all_records" },
120
+ "timezone": "Asia/Shanghai",
121
+ "rev": 1,
122
+ "total": null
123
+ }
124
+ }
125
+ ```
126
+ (`total` may be absent rather than null — see the pagination contract below.)
127
+ `data.data` rows are positional arrays aligned with the parallel `fields`, `field_id_list`,
128
+ `field_type_list`, and `record_id_list` arrays. Pagination contract (verified):
129
+ - `--offset` is a 0-based row skip; start at 0.
130
+ - `--limit` is 1–200 (default 100).
131
+ - After each page, advance `offset` by **the number of rows returned**, not by `limit` — a
132
+ short final page must not skip rows.
133
+ - Loop until `has_more: false`. `total` is null or absent in this envelope — never use it to
134
+ detect the end.
135
+ - Each page's `fields` order is authoritative for **that page**. Field-list order ≠
136
+ record-list order, and `--field-id` projection re-aligns the parallel arrays — always zip
137
+ with the `fields` array from the same response.
138
+ 3. **Zip each page into per-record objects.** The flat snapshot reserves `__record_id` for the
139
+ stable ID returned by the Bitable API. Record `i` becomes
140
+ `{ __record_id: record_id_list[i], fields[j]: data[i][j] for each j }`. A business field named
141
+ `record_id` remains an ordinary source column. If the table itself contains a business field
142
+ named `__record_id`, stop before writing any snapshot instead of overwriting either value or
143
+ silently renaming the user's field. Reference implementation (paginates, zips, writes
144
+ `snapshot.jsonl`, prints a summary only — no record values):
145
+ ```javascript
146
+ import { execFileSync } from "node:child_process";
147
+ import { mkdirSync, writeFileSync } from "node:fs";
148
+ import path from "node:path";
149
+
150
+ const [baseToken, tableId, outDir] = process.argv.slice(2);
151
+ mkdirSync(outDir, { recursive: true });
152
+
153
+ function fetchPage(offset) {
154
+ const stdout = execFileSync(
155
+ "lark-cli",
156
+ ["base", "+record-list", "--base-token", baseToken, "--table-id", tableId,
157
+ "--offset", String(offset), "--limit", "200", "--format", "json"],
158
+ { encoding: "utf8", timeout: 120_000,
159
+ env: { ...process.env,
160
+ LARKSUITE_CLI_NO_UPDATE_NOTIFIER: "1",
161
+ LARKSUITE_CLI_NO_SKILLS_NOTIFIER: "1" } }
162
+ );
163
+ return JSON.parse(stdout);
164
+ }
165
+
166
+ const RECORD_ID_KEY = "__record_id";
167
+ let offset = 0; const records = []; let meta = null;
168
+ while (true) {
169
+ const envelope = fetchPage(offset);
170
+ if (!envelope.ok) { console.error("record-list failed:", JSON.stringify(envelope.error ?? envelope)); process.exit(1); }
171
+ const d = envelope.data;
172
+ const rows = d.data ?? [], ids = d.record_id_list ?? [], fields = d.fields ?? [];
173
+ if (rows.length !== ids.length) { console.error(`row/id length mismatch: rows=${rows.length} ids=${ids.length}`); process.exit(1); }
174
+ if (fields.includes(RECORD_ID_KEY)) { console.error(`reserved field name collision: ${RECORD_ID_KEY}`); process.exit(1); }
175
+ for (let i = 0; i < rows.length; i++) {
176
+ const rec = { [RECORD_ID_KEY]: ids[i] };
177
+ for (let j = 0; j < fields.length; j++) rec[fields[j]] = rows[i][j];
178
+ records.push(rec);
179
+ }
180
+ meta = { timezone: d.timezone, rev: d.rev, total: d.total, fieldNames: fields };
181
+ if (!d.has_more) break;
182
+ offset += rows.length;
183
+ }
184
+
185
+ const outPath = path.join(outDir, "snapshot.jsonl");
186
+ writeFileSync(outPath, records.map((r) => JSON.stringify(r)).join("\n") + "\n", "utf8");
187
+ console.log(JSON.stringify({ snapshotPath: outPath, records: records.length,
188
+ fieldCount: meta.fieldNames.length, fieldNames: meta.fieldNames,
189
+ timezone: meta.timezone, rev: meta.rev, totalReported: meta.total }));
190
+ ```
191
+ Optional scoping flags (all verified; default is all records, all fields): `--field-id
192
+ <name|id>` (repeatable) projects to specific fields; `--view-id` reads a specific view;
193
+ `--filter-json` overrides the view's own filter, e.g.
194
+ `{"logic":"and","conditions":[["Title","==","Launch plan"]]}` (equality),
195
+ `[["Title","intersects","urgent"]]` (contains), `[["Score","==",95]]` (numbers unquoted);
196
+ `--sort-json` (max 10 rules) overrides the view's sort, e.g.
197
+ `[{"field":"Updated","desc":true}]`.
198
+
199
+ Field-type mapping and value shapes in the snapshot:
200
+
201
+ | Bitable field type | `--format json` value shape | Downstream `inspect` inference |
202
+ | --- | --- | --- |
203
+ | text, `style.type: plain/phone/email/barcode` | string | string |
204
+ | text, `style.type: url` | **markdown link** `[display](url)`, not the raw URL | string — the markdown wrapper is part of the value |
205
+ | number (plain/currency/progress/rating; `style` is display-only) | plain number | number |
206
+ | checkbox | boolean | boolean |
207
+ | select, `multiple: false` (single-select) | **single-element array** (e.g. `["paid"]`) | **`list`**, not string |
208
+ | select, `multiple: true` (multi-select) | array of strings; **empty selection is `null`, not `[]`** | `list` (empty rows counted as missing) |
209
+ | datetime (any `style.format`) | full ISO8601 string with offset; envelope `timezone` states the base timezone | datetime |
210
+ | created_at / updated_at | full ISO8601 string | datetime |
211
+ | auto_number | string (e.g. `NO.001`) | string |
212
+ | created_by / updated_by | array of `{id, name}` user objects (single-element for one creator) | `list` |
213
+ | location | object `{lng, lat, full_address}` | json/object |
214
+ | link | array of `{id}` record refs (single-element for one link) | `list` |
215
+ | attachment | `null` when empty (verified); non-empty values are out of scope | all-null column |
216
+ | formula | **always a string, even for numeric results** (e.g. `"20"`) | string |
217
+ | lookup | data-dependent: scalar string for a single `raw_value` match; list for multiple matches or a list aggregate | string or list |
218
+
219
+ Warnings the mapping step must carry:
220
+
221
+ - single-select columns infer as `list` (not `string`) because Bitable returns single-element
222
+ arrays — surface this when the user confirms the mapping.
223
+ - `created_by` / `updated_by` are **single-value** fields the API wraps in a one-element array
224
+ of `{id, name}` user objects — surface this when the user confirms the mapping, and do not
225
+ treat them as multi-value. The `id` is a Feishu open_id/user_id, not an AE identity; these
226
+ are audit metadata. Default to excluding them, or import only `name` as a plain `string`
227
+ property (after confirming with the user); do not map them to a `list` or an `{id, name}`
228
+ `object` unless the user explicitly asks. A custom **person** field is different:
229
+ single-person fields wrap the same way, multi-person fields are genuinely multi-value —
230
+ confirm which before mapping.
231
+ - `link` (single-link) columns infer as `list` because the API wraps a single link in a
232
+ one-element array of `{id}` record refs — surface this when the user confirms the mapping,
233
+ and do not treat them as multi-value. The `{id}` is the linked record's internal
234
+ `record_id`, not a business value: exclude the column, or flatten the linked record's real
235
+ fields via a `lookup`/`formula` on the source table instead of importing record_ids.
236
+ A multi-link field returns multiple `{id}` refs per row; `+field-list` exposes no
237
+ `multiple` flag for link fields, so distinguish single from multi by the value array
238
+ length across rows, not by a field-list property.
239
+ - `location` columns are objects `{lng, lat, full_address}` — mapping the whole column locks
240
+ an `object` property type. Usually only `full_address` (a plain string) is meaningful;
241
+ confirm whether to flatten it to that single string (or exclude) rather than default to
242
+ `object`.
243
+ - an empty multi-select is `null` (verified), so `inspect` counts those rows as missing — a
244
+ null multi-select is "no selection", not data loss.
245
+ - `url`-styled text fields come back as markdown links (`[display](url)`), not raw URLs —
246
+ strip the wrapper (or re-key from a plain text field) before mapping to a URL property.
247
+ - formula fields are always strings in the snapshot, even when the expression is numeric
248
+ (e.g. `"20"`) — inspect infers `string`; do not expect a number column.
249
+ - lookup value shape depends on the aggregate, the target field type, and the match count —
250
+ a lookup to a person field returns `{id, name}` objects, to a select field returns option
251
+ strings (possibly a list), to a scalar text/number field returns a scalar string or list —
252
+ so confirm the target field type per-table before mapping.
253
+ - attachment fields are kept as an all-null column when empty; downloading attachments
254
+ (`base +record-download-attachment`) is out of scope for ingestion.
255
+ 4. If pagination fails on a network error or times out mid-loop, treat the snapshot as unknown:
256
+ do not write or keep a partial file; stop, and ask the user to confirm the base state before
257
+ retrying — the same rule as a lost upload batch.
258
+
259
+ ## Step 3 — Rejoin the local-file pipeline
260
+
261
+ Feed the snapshot as a local file and continue at [source-inspect.md](source-inspect.md):
262
+
263
+ ```bash
264
+ ae-cli data-integration inspect --input-file '.ae-cli/data-integration/online/<fingerprint>/snapshot.jsonl'
265
+ ```
266
+
267
+ The zip step prefixes each record with reserved `__record_id` — a stable per-record key from the
268
+ Bitable API, useful as a dedup key downstream. A source `record_id` column remains intact; a source
269
+ `__record_id` column blocks snapshot creation as a reserved-name collision. Expect the Step 2
270
+ inference notes to show up here: single-select columns surface as `list`, empty multi-selects as
271
+ missing rows. Everything downstream — business identification, tracking plan, transform, sink —
272
+ is unchanged. The snapshot lives under
273
+ `.ae-cli/data-integration/`, so [reuse](reuse.md) and [handoff](handoff.md) find it like any other
274
+ pipeline artifact; record in the handoff that the source was an online Feishu Bitable, the base
275
+ and table, and include the snapshot timestamp and base timezone.
276
+
277
+ ## Error classification
278
+
279
+ The three pipeline classes in [error-handling.md](error-handling.md) are about rows, files, and
280
+ programs. Online-source problems land outside those three and must not be mislabeled as them:
281
+
282
+ | Problem | Class it is NOT | What to do |
283
+ | --- | --- | --- |
284
+ | `lark-cli` not installed | Not a parse error, not a data problem | Stop; give the install command |
285
+ | lark-cli not logged in / no user identity | Not a parse error | Split-flow authorization with the user |
286
+ | Missing scope (`permission_violations`) | Not a parse error | Incremental `auth login --scope` (user) or developer console (bot) |
287
+ | Base/table not accessible to the user's account | Not a scope problem | Ask the user to verify the link and their access |
288
+ | `+record-list` network failure / timeout mid-pagination | Same rule as a lost upload batch | Treat the snapshot as unknown; stop and confirm |
@@ -0,0 +1,130 @@
1
+ # Source — online document (Feishu sheet)
2
+
3
+ ## When this branch applies
4
+
5
+ The input is a **URL**, not a local path. Feishu sheet links (`/sheets/`), spreadsheet links
6
+ (`/spreadsheets/`), and wiki links that resolve to a sheet (`/wiki/`) all route here instead of
7
+ [source-inspect.md](source-inspect.md). The pipeline is identical after the sheet is snapshotted
8
+ to a local XLSX: business identification, tracking plan, transform, and sink all reuse the
9
+ local-file flow unchanged.
10
+
11
+ Only **Feishu sheets** and **Feishu Bitable (多维表格)** are supported in this phase. Bitable links
12
+ (`/base/`) — including wiki links that resolve to a Bitable — route to
13
+ [lark-bitable-source.md](lark-bitable-source.md) instead of this page. Other online documents
14
+ (Tencent Docs, DingTalk, WPS, Google Sheets, Notion) have no CLI read path — route to
15
+ [manual-export-source.md](manual-export-source.md), which has the user export the file themselves
16
+ and then rejoins the local-file flow.
17
+
18
+ ## Safety rules (online-specific)
19
+
20
+ - The URL, its token, the snapshot file path, and every cell value are sensitive. Never print
21
+ source values while inspecting; summarize types, ratios, counts, and fingerprints only.
22
+ - Pulling a sheet to the local machine moves data across a trust boundary. Before downloading
23
+ anything, tell the user the sheet will be snapshotted to a local file, and get their
24
+ confirmation when the sheet is not their own data.
25
+ - The snapshot is a point-in-time copy. State the export timestamp, and note that the import
26
+ reflects the exported moment only — a sheet that may be edited mid-run is imported as of the
27
+ snapshot, not live.
28
+ - lark-cli (Feishu) and ae-cli (AE) are two separate credential domains. Read Feishu with
29
+ lark-cli; upload to AE with ae-cli. Never forward a token from one to the other, and never
30
+ send an AE access token or CLI token to any Feishu endpoint.
31
+
32
+ ## Step 0 — Environment self-check (before any pull)
33
+
34
+ The Feishu read path depends on `lark-cli`, a CLI separate from ae-cli. Check it up front so a
35
+ missing install or a missing login surfaces as an environment problem, not as a data problem
36
+ mid-pipeline.
37
+
38
+ 1. **Detect lark-cli.** Run `lark-cli --version`. If the command is not found, stop and tell the
39
+ user to install it (`npm i -g @larksuite/cli`). Do not attempt to install it yourself, and do
40
+ not fall back to another read path — a half-provisioned Feishu client produces worse failures
41
+ than a clear "not installed" stop.
42
+ 2. **Check the login.** Run
43
+ `LARKSUITE_CLI_NO_UPDATE_NOTIFIER=1 LARKSUITE_CLI_NO_SKILLS_NOTIFIER=1 lark-cli auth status --json --verify`.
44
+ Reading a sheet in the user's cloud space needs the **user** identity (`--as user`); the bot
45
+ identity cannot see a user's drive documents. If the user identity is unavailable or
46
+ unverified, follow the lark-shared skill's split-flow: start
47
+ `lark-cli auth login --scope "<scope>" --no-wait --json`, show the QR code / link to the user,
48
+ and only after the user confirms run `lark-cli auth login --device-code <device_code>`.
49
+ Authorization requires the user's participation — never bypass or automate it.
50
+ 3. **Handle permission errors when they occur.** If a pull returns `permission_violations`
51
+ (missing scopes) together with `console_url` and `hint`, route by identity:
52
+ - user identity → add the missing scope with
53
+ `lark-cli auth login --scope "<missing_scope>"` (incremental grant);
54
+ - bot identity → direct the user to open the scope in the developer console via the returned
55
+ `console_url`; never run `auth login` for a bot.
56
+ If the sheet itself is not accessible to the user's account — a resource-side permission
57
+ problem, not a scope problem — ask the user to confirm the link is correct and that their
58
+ Feishu account can open the sheet. Do not retry against a different sheet silently.
59
+
60
+ ## Step 1 — Locate the workbook and sheets
61
+
62
+ 1. Run `lark-cli sheets +workbook-info --url "<url>"` to list the sheets (`sheet_id`, `title`,
63
+ `row_count`, `column_count`, `is_hidden`). Never guess a sheet id or the name `Sheet1`.
64
+ 2. Surface the sheet list to the user. A workbook with one visible sheet proceeds with it;
65
+ multiple sheets ask the user to choose, mirroring `--data-set` on a local workbook. Report any
66
+ hidden sheet (`is_hidden`) by name — it is usually scratch space or a superseded draft, and
67
+ the same "ask before reading a hidden sheet" rule as a local XLSX applies. (`inspect` already
68
+ excludes hidden sheets from discovery, listing them under `excluded_sheets` with reason
69
+ `hidden` — name them anyway rather than relying on silent exclusion.) Show each sheet's row
70
+ count and, when available, its time coverage so an overlapping or derived sheet is visible
71
+ before it is chosen.
72
+
73
+ ## Step 2 — Snapshot to a local XLSX
74
+
75
+ Export the workbook to an XLSX under the pipeline's working directory (a cwd-relative path, so
76
+ lark-cli's file-path rules accept it):
77
+
78
+ ```bash
79
+ lark-cli sheets +workbook-export --url "<url>" --output-path ".ae-cli/data-integration/online/<fingerprint>/snapshot.xlsx"
80
+ ```
81
+
82
+ - **Export the whole workbook as XLSX**, not CSV: the XLSX export preserves dates, numbers,
83
+ merged cells, and hidden rows, so the downstream XLSX reader (date-cell detection, merged
84
+ cells, hidden rows) and the type inference behave exactly as for a local file. One caveat
85
+ (verified): the export keeps a formula's text but **drops the cached computed result**, so a
86
+ formula cell reads as missing — `inspect` flags it with a warning naming the affected columns
87
+ ("a formula whose last computed result is not stored in the file"). Surface that warning when
88
+ the source sheet contains formulas; the skill never evaluates a formula or guesses its value.
89
+ Do **not** use `+csv-get` for the snapshot — its display values round long numbers to
90
+ scientific notation (`1.04E+14`) and flatten types, which would silently corrupt ID-like
91
+ columns and lock wrong property types in AE.
92
+ - `<fingerprint>` is a short, collision-resistant name derived from the spreadsheet token plus a
93
+ timestamp (e.g. first 8 chars of the token hash + `YYYYMMDD-HHMMSS`). One online source gets
94
+ one directory, so a re-export never overwrites an unrelated source. Create the directory before
95
+ exporting.
96
+ - The export is an async job with built-in polling. If it returns `timed_out=true`, resume with
97
+ its `next_command` rather than re-exporting blindly.
98
+ - If the export fails on a network error or times out mid-job, treat the snapshot as unknown:
99
+ stop, and ask the user to confirm the sheet state before retrying — the same rule as a lost
100
+ upload batch. Never resume a half-written snapshot silently.
101
+
102
+ ## Step 3 — Rejoin the local-file pipeline
103
+
104
+ Feed the snapshot as a local file and continue at [source-inspect.md](source-inspect.md):
105
+
106
+ ```bash
107
+ ae-cli data-integration inspect --input-file '.ae-cli/data-integration/online/<fingerprint>/snapshot.xlsx'
108
+ ```
109
+
110
+ When the exported workbook holds multiple sheets, pass `--data-set '<chosen-sheet>'` using the
111
+ sheet the user picked in Step 1 — the downstream multi-sheet selection is answered by the same
112
+ choice, not re-asked.
113
+
114
+ Everything downstream — business identification, tracking plan, transform, sink — is unchanged.
115
+ The snapshot lives under `.ae-cli/data-integration/`, so [reuse](reuse.md) and
116
+ [handoff](handoff.md) find it like any other pipeline artifact; record in the handoff that the
117
+ source was an online Feishu sheet and include the snapshot timestamp.
118
+
119
+ ## Error classification
120
+
121
+ The three pipeline classes in [error-handling.md](error-handling.md) are about rows, files, and
122
+ programs. Online-source problems land outside those three and must not be mislabeled as them:
123
+
124
+ | Problem | Class it is NOT | What to do |
125
+ | --- | --- | --- |
126
+ | `lark-cli` not installed | Not a parse error, not a data problem | Stop; give the install command |
127
+ | lark-cli not logged in / no user identity | Not a parse error | Split-flow authorization with the user |
128
+ | Missing scope (`permission_violations`) | Not a parse error | Incremental `auth login --scope` (user) or developer console (bot) |
129
+ | Sheet not accessible to the user's account | Not a scope problem | Ask the user to verify the link and their access |
130
+ | Export job timed out / network lost | Same rule as a lost upload batch | Treat the snapshot as unknown; stop and confirm |
@@ -1,5 +1,7 @@
1
1
  # Local analysis
2
2
 
3
+ Dimension / dictionary data (a stable-entity lookup with a join key) is not local-analysis material — it routes to ae-metadata as a dimension table. See [ue-routing.md](ue-routing.md) and [dimension-routing.md](dimension-routing.md).
4
+
3
5
  Keep the source on the local machine. Generated scripts and reports belong under `.ae-cli/data-integration/runs/<run-id>/` with restrictive permissions.
4
6
  Set the directory to `0700` and generated scripts/reports to `0600`.
5
7
 
@@ -0,0 +1,83 @@
1
+ # Source — online document, manual export (Tencent Docs / DingTalk / WPS)
2
+
3
+ ## When this branch applies
4
+
5
+ The input is a **URL** that points to an online document on a platform other than Feishu:
6
+ Tencent Docs (`docs.qq.com`), DingTalk docs, WPS / Kingsoft Docs (`kdocs.cn`), Google Sheets,
7
+ Notion, and the like. These platforms have **no CLI read path** in this phase — only Feishu has
8
+ one, via lark-cli (see [lark-sheet-source.md](lark-sheet-source.md) and
9
+ [lark-bitable-source.md](lark-bitable-source.md)). There is therefore no automatic snapshot here:
10
+ the user exports the document to a local file themselves, and the pipeline rejoins at the
11
+ local-file flow unchanged.
12
+
13
+ ## Safety rules
14
+
15
+ - The URL and every exported cell value are sensitive. Never print source values while
16
+ inspecting; summarize types, ratios, counts, and fingerprints only.
17
+ - The export is a point-in-time copy made by the user on the source platform. State the export
18
+ timestamp, and note that the import reflects the exported moment only — a document edited
19
+ mid-run is imported as of the export, not live.
20
+ - The export is the user's own action on the source platform. Do not automate it, and do not ask
21
+ for that platform's credentials — there is no Feishu-style OAuth to run on this branch.
22
+
23
+ ## Step 1 — Recognize the platform and route
24
+
25
+ Inspect the URL's host to confirm it is not Feishu. Feishu hosts (`feishu.cn`, `larksuite.com`)
26
+ route to the two lark source pages instead of this one; any other online-document host
27
+ (`docs.qq.com`, `kdocs.cn`, a DingTalk docs host, etc.) lands here. If the host is ambiguous,
28
+ ask the user which platform the link belongs to rather than guessing.
29
+
30
+ ## Step 2 — Guide the user to export
31
+
32
+ Ask the user to export the document from the source platform's own UI to a local file, and to
33
+ name the file so its origin is traceable. Give only the general route — the exact menu labels
34
+ differ by platform and change over time, so follow the platform's current export UI rather than a
35
+ memorized click path:
36
+
37
+ - open the document, then use the platform's export / save-as / download action;
38
+ - choose **XLSX** (Excel workbook) where offered, not CSV — CSV flattens types, may round long
39
+ ID-like numbers to scientific notation, and loses multiple sheets. This is the same reason the
40
+ Feishu sheet flow snapshots XLSX, not CSV (see
41
+ [lark-sheet-source.md](lark-sheet-source.md));
42
+ - if the platform only offers CSV, accept it but flag the type-flattening risk to the user, and
43
+ watch for ID-like columns that must stay text;
44
+ - ask the user to place the file under the pipeline's working directory (e.g.
45
+ `.ae-cli/data-integration/manual/<fingerprint>/<name>.xlsx`) so [reuse](reuse.md) and
46
+ [handoff](handoff.md) find it like any other pipeline artifact.
47
+
48
+ Export-time caveats to surface to the user — platform-dependent, and the same rules as a local
49
+ file:
50
+
51
+ - **multiple sheets** — the export may contain several sheets; confirm which one is the data set,
52
+ mirroring `--data-set` on a local workbook.
53
+ - **formulas** — an exported formula cell may carry only its text, not the cached computed result;
54
+ `inspect` flags such cells as missing. The skill never evaluates a formula or guesses its value.
55
+ - **hidden rows/columns/sheets** — the platform may drop or keep hidden content depending on its
56
+ export; `inspect` excludes what it can detect (hidden sheets appear under `excluded_sheets`),
57
+ but ask the user to confirm the export contains what they expect before profiling.
58
+ - **dates / encoding** — prefer a UTF-8 export; if dates arrive as text, say so rather than
59
+ silently coercing them.
60
+
61
+ ## Step 3 — Rejoin the local-file pipeline
62
+
63
+ Feed the exported file as a local file and continue at [source-inspect.md](source-inspect.md):
64
+
65
+ ```bash
66
+ ae-cli data-integration inspect --input-file '<exported-file>'
67
+ ```
68
+
69
+ When the export holds multiple sheets, pass `--data-set '<chosen-sheet>'` using the sheet the
70
+ user picked in Step 2. Everything downstream — business identification, tracking plan, transform,
71
+ sink — is unchanged. Record in the handoff that the source was a manually-exported online
72
+ document, name the platform and the export timestamp, and include the exported file path.
73
+
74
+ ## Error classification
75
+
76
+ The three pipeline classes in [error-handling.md](error-handling.md) are about rows, files, and
77
+ programs. Manual-export problems land outside those three and must not be mislabeled as them:
78
+
79
+ | Problem | Class it is NOT | What to do |
80
+ | --- | --- | --- |
81
+ | Platform only exports CSV; types flatten | Not a parse error | Flag the risk; watch ID-like columns |
82
+ | Export is missing sheets / rows the user expects | Not a data problem yet | Ask the user to re-export or confirm the data set |
83
+ | URL host is unrecognized and not Feishu | Not a routing failure | Ask the user which platform the link belongs to |
@@ -37,6 +37,8 @@ node .ae-cli/data-integration/<fingerprint[:16]>/transform.mjs <new-input-file>
37
37
 
38
38
  Do **not** run the returned command on your own. Show the user the proposed package — the frozen event name, the property mapping it implies, and the fact that the confirmed business logic (event name, `value_mapping`, flatten rules) is reused unchanged — and wait for one explicit confirmation. Before confirming, diff the new file's flattened properties against the package's `plan.json`: if the package has no `plan_file`, or the new file produces properties the plan does not cover, run the Tracking plan step to add them (merge into the existing project plan) first. Only then run `transform.mjs` on the new file and continue to Sink.
39
39
 
40
+ The frozen mapping's `#type`/`mode` (e.g. `track`) is authoritative after a match — ignore `inspect`'s auto recommendation, which may re-infer `user_set` for a package whose confirmed mapping is `track`. A reuse match must not re-do Source identification or event-model inference.
41
+
40
42
  ## Safety rules
41
43
 
42
44
  - Reuse only for a file of the **same shape** (same header/schema and format). The `transform.mjs` wrapper re-binds the content fingerprint to the new file, so the content guard still applies per run.
@@ -31,10 +31,42 @@ ae-cli data-integration upload \
31
31
  --dry-run
32
32
  ```
33
33
 
34
+ Before the confirmation gate, re-check the project's **runtime-locked** property types. A `reuse` match skips the tracking-plan step, so this check is the one that must not be bypassed on any path — repeat it for every upload:
35
+
36
+ ```bash
37
+ ae-cli analysis-meta property list -p <project-id> --table-type user
38
+ ae-cli analysis-meta property list -p <project-id> --table-type event
39
+ ```
40
+
41
+ Diff each target property name against `select_type` (the locked type). A same-name property whose locked type disagrees with the mapping's type drops those values silently at ingest, even when the plan layer agrees — surface any such conflict in the confirmation gate (rename the target, or change the mapped type to match the locked one) before asking the user to confirm. This is a read-only check; do not run `ae-cli tracking plan sync-from-meta` here, which writes the plan.
42
+
34
43
  Show the masked target, project, file fingerprint, record count, quarantined count, batch count, and persistence limitation. Re-state the system-field mapping first (`#type`/mode, `#account_id`, `#distinct_id`, `#time` + source timezone, `#event_name`), then re-list the final property mapping for every file or sheet being uploaded — source column → target AE name → type (+ `display_name`/`desc` when set), grouped into event properties (`track`) and user properties (profile modes), with each event's attached properties listed — never a counts-only summary. For a multi-sheet workbook, group by sheet. Wait for explicit confirmation. Execute the same command without `--dry-run` only after confirmation. For a blocked manifest, first show the quarantine statistics and separately ask whether the user accepts uploading only valid rows; add `--allow-clean-subset` only after a clear yes.
35
44
 
36
45
  `status=receiver_accepted` means receiver acceptance only, not durable storage. Say that persistence remains unverified. Never report success on this status alone.
37
46
 
47
+ `upload` is **not idempotent** — every execution submits to the receiver again. Never re-run the
48
+ command to inspect a response: read the first run's saved JSON output instead. `--dry-run` only
49
+ previews the request it would send; it neither executes nor previews the receiver's real response.
50
+
51
+ The execute success response reports the receiver outcome under **different field names than the
52
+ dry-run preview** — do not reuse the dry-run names (`record_count` / `batch_count`) when reading
53
+ it:
54
+
55
+ | field | meaning |
56
+ | --- | --- |
57
+ | `status` | `receiver_accepted` (or `partially_delivered` when `--retry` salvaged some records) |
58
+ | `delivery_state` | `receiver_accepted` / `partially_delivered` |
59
+ | `submitted_records` | records submitted this run (equals `record_count - resume_from` on a clean run) |
60
+ | `submitted_batches` | batches sent this run |
61
+ | `resume_from` | zero-based offset this run started at |
62
+ | `request_bytes` / `response_bytes` | transport byte counts |
63
+ | `persistence_verified` | always `false` — receiver acceptance is not durable storage |
64
+ | `next_step` | the verification guidance |
65
+
66
+ `--retry` salvage additionally reports `failed_records` / `failed_count`. A lost batch is reported
67
+ as `delivery_state=unknown` in the error's `meta`, not in the success fields — see
68
+ [sync-json-upload.md](sync-json-upload.md) "Interrupted delivery".
69
+
38
70
  ## Verify the data landed
39
71
 
40
72
  Ingestion is asynchronous — expect about a 1-minute delay between `receiver_accepted` and the data being queryable. Instead of telling the user to check in the console, offer to verify with ae-cli (control-plane commands; require the CLI to be logged in to the AE host and a project-id):
@@ -63,7 +63,7 @@ Summarize both — report the shape of the distribution and the names of the val
63
63
  - **Excel date cells** — a cell whose number format is a date or date+time is read as the wall-clock timestamp shown in Excel, not as the Excel serial number stored behind it, so the column infers as `datetime` and can serve as the time field. Inspect lists every such column in a warning. Treat that warning as a question to the user, not as a note: the same column profiled as `number` before this behavior existed, so if any part of this file was already sent to AE, the property may have been received as a number and its type is now locked — it cannot be changed to datetime, and the column has to be re-sent under a new property name. Ask whether the column was uploaded before, and only map it once the user answers. Elapsed-duration formats (`[h]:mm:ss` and the equivalent built-ins) are durations rather than points in time and stay `number`.
64
64
  - **Excel formula cells** — a spreadsheet stores a formula and, next to it, the result Excel last computed. That cached result is the value: it is read normally, including a result of `0` or `""`, which are real values and not blanks. This tool never evaluates a formula and never guesses a result, so a cell holding a formula the file never computed has nothing to upload; it is read as missing and counted, as is an Excel error value (`#N/A`, `#DIV/0!`, …). Inspect reports the counts per column in a warning and `convert` repeats them in `manifest.output.unreadable_cells`. Report them: the rows are kept and the record count is unchanged, so this is the only explanation for a column that is empty in AE while the spreadsheet looks full. When a column that matters reads as missing this way, ask the user to recalculate and re-export in Excel, or to export values instead of formulas, before uploading. This covers XLSX; a legacy `.xls` workbook goes through a different parser and is not counted here.
65
65
  - **Merged cells, hidden rows, and hidden columns** — a sheet maintained by hand merges a label down the rows it covers (`区域` spanning one region's block). Excel keeps that value on the block's first row only and stores every row below it as an empty cell, so a column that looks full on screen arrives mostly missing, and the AE property built from it would be empty for most events. The same worksheet may also hide a row inside a data block or hide a whole column. None of this travels with a row, so inspect scans the worksheet structure separately and reports it under `xlsx_structure`: `merged_ranges` with `merged_range_samples` (references such as `A3:A5`, never cell text), `merged_covered_cells` per column, `hidden_rows` with `hidden_row_samples` (source row numbers as Excel numbers them), and `hidden_columns` by header name. The default read is unchanged, so the report is a question for the user, and each answer is a flag: `--fill-merged-cells` copies each block's value into the cells its own range covers — bounded to the range, never overwriting a value that is there and never inventing one when the block's own cell is empty, so it is not a forward fill; `--exclude-hidden-rows` leaves hidden rows out. Neither is on by default: those cells really are empty in the file, and a row hidden inside a data block may still be real data — unlike a hidden *worksheet* (below), which is excluded by default. Hidden columns have no flag at all; when the user confirms one is not data, list it in the mapping's `exclude_columns`. Both flags are carried into the recommended mapping as `fill_merged_cells` / `exclude_hidden_rows`, which is what makes `convert` read the rows inspect profiled — `convert` has no read flags of its own — and `convert` repeats the findings in `manifest.output.xlsx_structure`, the only record of a layout the converted rows no longer show. This covers XLSX; a legacy `.xls` workbook is not scanned, so ask the user about merged labels and hidden rows there instead of trusting silence.
66
- - **Hidden worksheets** — a worksheet hidden in the workbook is left out of the `--data-set` candidates and out of `--merge-sheets`, because a sheet the file does not show is usually scratch space, a lookup table, or a superseded draft rather than rows anyone meant to upload. Inspect lists each one under `excluded_sheets` (with `reason: hidden`); report those names to the user, since they are the only explanation for a row count lower than the workbook appears to hold. Their headers are also left out of `header_consistency`, so a stale hidden draft cannot make a mergeable workbook look ragged. A hidden sheet stays readable when the user names it in `--data-set` — the command then warns on stderr that the selected sheet is hidden. Only pass a hidden sheet after the user says that is what they want. When *every* worksheet is hidden there is no candidate left, and inspect fails with `LOCAL_DATA_ALL_DATA_SETS_HIDDEN` whose hint lists the hidden sheets; treat that as a question about which sheet holds the real data, not as an unreadable file. This detection covers XLSX only: a legacy `.xls` workbook's sheet list is unfiltered, so a hidden sheet there still appears as a candidate and is still merged — for `.xls`, ask the user to confirm the sheet list instead of trusting it.
66
+ - **Hidden worksheets** — a worksheet hidden in the workbook is left out of the `--data-set` candidates and out of `--merge-sheets`, because a sheet the file does not show is usually scratch space or a superseded draft rather than rows anyone meant to upload, but a hidden sheet can also be a dimension / dictionary table that is meant to be loaded, and that goes through dimension routing instead of being dismissed as scratch. Inspect lists each one under `excluded_sheets` (with `reason: hidden`); report those names to the user, since they are the only explanation for a row count lower than the workbook appears to hold. Their headers are also left out of `header_consistency`, so a stale hidden draft cannot make a mergeable workbook look ragged. A hidden sheet stays readable when the user names it in `--data-set` — the command then warns on stderr that the selected sheet is hidden. Only pass a hidden sheet after the user says that is what they want. When *every* worksheet is hidden there is no candidate left, and inspect fails with `LOCAL_DATA_ALL_DATA_SETS_HIDDEN` whose hint lists the hidden sheets; treat that as a question about which sheet holds the real data, not as an unreadable file. This detection covers XLSX only: a legacy `.xls` workbook's sheet list is unfiltered, so a hidden sheet there still appears as a candidate and is still merged — for `.xls`, ask the user to confirm the sheet list instead of trusting it.
67
67
  - **Excel sheets** — `--merge-sheets` streams every visible worksheet in file order instead of a single selected sheet; otherwise ask which sheet/`--data-set` to use. Inspect also reports `header_consistency` (`all_same` or `different`) across a workbook's sheets, with `header_details` listing each sheet's header row when they differ; prefer `--merge-sheets` only when headers match. Matching headers establish a shared structure, not disjoint rows: a detail sheet and a summary sheet, or `1月` and `1月修订版`, usually carry identical headers and would be merged and reported twice over. Before merging, confirm with the user that the sources are mutually exclusive partitions (one month per sheet, no overlap) rather than overlapping, revised, or derived views of the same rows, and show each sheet's row count and time coverage range in that confirmation so an overlap is visible. The same rule applies to repeated `--input-file`.
68
68
  - **Multi-file type conflicts** — when the same column has different inferred types across files, present each conflict and resolve with `--type-resolutions` on `convert` (see [transform](transform.md)).
69
69
 
@@ -10,9 +10,12 @@ Generate and confirm the event/property plan **before** any transform or upload.
10
10
  ## Sub-steps
11
11
 
12
12
  1. **Event-model decision** — reuse the UE routing result: single-table single-event `track`, single-table multi-event (event-name column), `user_set`, or `mixed`. The agent may propose splitting one table into several events (for example an ad table into `ad_show`/`ad_click` by `campaign_type`); that proposal must be confirmed by the user in the confirmation gate.
13
- 2. **Column → property draft** — confirm the recommended mapping's key system fields with the user **before** drafting: `mode` (`#type`), `#account_id`/`#distinct_id` (ask together; at least one is required — a `user_id` column can be either an anonymous or a login ID and only the user knows), `#time` + source timezone + `#zone_offset`, `#event_name` (track only; the event column or a reviewed `default_event_name`), and `#ip`/`#uuid` when the data has such a column. The exact questions and the never-infer-from-a-column-name-alone rule are [transform.md](transform.md) steps 1–5; run them here. The plan is generated from this mapping, so never draft from an unconfirmed mapping. With the system fields settled, map the remaining columns to event and/or user properties (the mapping `mode` decides). Common event properties — project-level super properties attached to every event — are defined by `ae-generate-tracking-plan`, not this import path. Name events and properties in snake_case and fill **every** `display_name`, `desc`, and `event_tag` (events also carry `event_desc`). Infer all three from field names, value distribution, samples, and business-doc / prompt priors — never leave them empty: `desc`/`event_desc` state what the item means in plain language (language follows the user), and `event_tag` picks the closest category from the canonical tag list (see the `event_tag` appendix in `../../ae-generate-tracking-plan/references/business-dimension-mapping.md`). When you cannot infer a `desc` or `event_tag`, mark it pending and ask the user for it inside the confirmation gate. Infer types (`number` / `bool` / `datetime` / enum) the same way; CSV defaults to `string`. Columns that stay uncertain or conflicting are marked pending and asked only inside the confirmation gate.
13
+ 2. **Column → property draft** — confirm the recommended mapping's key system fields with the user **before** drafting: `mode` (`#type`), `#account_id`/`#distinct_id` (ask together; at least one is required — a `user_id` column can be either an anonymous or a login ID and only the user knows), `#time` + source timezone + `#zone_offset`, `#event_name` (track only; the event column or a reviewed `default_event_name`), and `#ip`/`#uuid` when the data has such a column. The exact questions and the never-infer-from-a-column-name-alone rule are [transform.md](transform.md) steps 1–5; run them here. The plan is generated from this mapping, so never draft from an unconfirmed mapping. With the system fields settled, map the remaining columns to event and/or user properties (the mapping `mode` decides). Common event properties — project-level super properties attached to every event — are defined by `ae-generate-tracking-plan`, not this import path. Name events and properties in snake_case by default (keep an uppercase event name only when the user asks to preserve it; property names stay lowercase-only) and fill **every** `display_name`, `desc`, and `event_tag` (events also carry `event_desc`). Infer all three from field names, value distribution, samples, and business-doc / prompt priors — never leave them empty: `desc`/`event_desc` state what the item means in plain language (language follows the user), and `event_tag` picks the closest category from the canonical tag list (see the `event_tag` appendix in `../../ae-generate-tracking-plan/references/business-dimension-mapping.md`). When you cannot infer a `desc` or `event_tag`, mark it pending and ask the user for it inside the confirmation gate. Infer types (`number` / `bool` / `datetime` / enum) the same way; CSV defaults to `string`. Columns that stay uncertain or conflicting are marked pending and asked only inside the confirmation gate.
14
14
  3. **Confirmation gate (single, one pass)** — present the concrete plan, never a counts-only summary: the confirmed key system-field mapping (`mode`, `#account_id`/`#distinct_id`, `#time` + source timezone, `#event_name`; `#ip`/`#uuid` when present), then a full event table (one row per event: `event_name` + `event_tag`/`event_desc` + the properties attached to it), then a full property table (one row per property: source column → target AE name → type → `display_name`/`desc`, uncertain types highlighted; a kept-whole `object`/`array_row` lists its `parent.child` sub-properties next to the parent), plus field scope (default: plan fields only, with a full-import switch) and unrecognized/dirty-data handling. For a multi-sheet workbook, group the property table by sheet so each sheet's source columns are visible. The user answers once with ok or edits (renames, types, identity/time/event columns, add/drop columns).
15
- 4. **Merge with the existing plan**fetch the project's current tracking plan; same-name property type conflicts are severe, same-name events are advisory; decide append vs replace. This runs for **every** file, not just the first: when the project already has a plan (an earlier file or run), diff this file's events and properties against it and put the additions new events, new properties, new object sub-properties from flattening — in the confirmation gate. An existing plan is never a reason to skip this step; only when every addition is already present may you skip the merge, and even then state and confirm that fact with the user.
15
+ 4. **Merge with the existing plan — and the project's runtime property metadata.** This runs for **every** file, not just the first, and it checks **two layers**, which are separate stores:
16
+ - **Plan layer (declarative)** — `ae-cli tracking plan fetch -p <project-id>`: same-name property type conflicts are severe, same-name events are advisory; decide append vs replace.
17
+ - **Runtime metadata layer (authoritative)** — `ae-cli analysis-meta property list -p <project-id> --table-type user` and `--table-type event`: each property's **locked** type is in `select_type`, and it is what actually gates ingestion. A same-name property whose `select_type` disagrees with the mapping's intended type is a **severe** conflict: those values are dropped silently at ingest even when the plan layer agrees with the mapping. Diff every target property name against this list, translating the mapping type to AE's runtime naming before comparing (`boolean` → `bool`, `list` → `array_string`), and put any mismatch in the confirmation gate (rename the target, or change the mapped type to match the locked one).
18
+ Diff this file's events and properties against both layers and put the additions — new events, new properties, new object sub-properties from flattening — in the confirmation gate. An existing plan is never a reason to skip this step; only when every addition is already present may you skip the merge, and even then state and confirm that fact with the user. Do not run `ae-cli tracking plan sync-from-meta` for this check — it is a write (it re-syncs the plan from metadata), not a read-only pre-flight.
16
19
  5. **Persist the plan** — `.ae-cli/data-integration/draft.json` → `.ae-cli/data-integration/draft.xlsx` → upload with `sdk_integration_mode=none`.
17
20
  6. **Hand off the field mapping** — the confirmed plan plus column→property mapping, `value_mapping`, and `flatten_rules` feed the Transform submodule.
18
21
 
@@ -17,7 +17,7 @@ Confirm the system fields with the user before touching properties. These are th
17
17
  4. **`#event_name` (track only).** Confirm the event-name column, or a reviewed `default_event_name` when no column exists.
18
18
  5. **`#ip` / `#uuid` (optional).** Ask only when the data has an IP- or UUID-like column; map it via `ip_field`/`uuid_field`, otherwise skip. `#ip` is event data only and must be a valid IPv4/IPv6 address (a private/LAN IP is kept but reported — AE cannot geolocate it); `#uuid` must be a standard 36-character UUID. A value that violates the spec is dropped from that row only (`INVALID_IP` / `INVALID_UUID`) — the row itself is kept. The program never auto-generates a `#uuid`.
19
19
 
20
- When an `#event_name`, `#account_id`, or `#distinct_id` column's values do not satisfy AE naming rules (pure Chinese, uppercase, spaces), do not stop — scan the distinct values, list them to the user, and ask for one AE-name replacement each; record the pairs in `value_mapping` (see [UE mapping](ue-mapping.md)). A value with no matching key keeps its original text and fails validation, so confirm every distinct value is covered or excluded. The same mechanism applies to a property column via that entry's own `value_mapping`.
20
+ When an `#event_name`, `#account_id`, or `#distinct_id` column's values do not satisfy AE naming rules (pure Chinese, spaces), do not stop — scan the distinct values, list them to the user, and ask for one AE-name replacement each; record the pairs in `value_mapping` (see [UE mapping](ue-mapping.md)). Event names are lowercased by default; keep an uppercase event name only when the user asks to preserve it — leave a legal uppercase value unmapped so it passes through, or map an illegal value to an uppercase target (e.g. `购买` → `Purchase`); see the casing rules in [UE mapping](ue-mapping.md). A value with no matching key keeps its original text and fails validation, so confirm every distinct value is covered or excluded. The same mechanism applies to a property column via that entry's own `value_mapping` — property names stay lowercase-only, so uppercase property values still need `value_mapping`.
21
21
 
22
22
  Then confirm the property set with the user before saving the mapping. Present every property as a readable table — one row per property with source column, target AE name, and type — never dump the raw mapping JSON at the user. Whether the rows are event or user properties follows `mode`: `track` → **event properties**, `user_set` (or another profile mode) → **user properties**, `mixed` → the same set applies to both event and user rows.
23
23