@thinkingai/ae-cli 6.1.20 → 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.
- package/README.md +2 -1
- package/README.zh.md +2 -1
- package/dist/{auth-FUM37MHF.js → auth-XZNXFRJS.js} +5 -5
- package/dist/{capability-AXFQW5WM.js → capability-FYTU3X6L.js} +42 -12
- package/dist/{chunk-LNZBEQXW.js → chunk-4NRCTUZJ.js} +27041 -474
- package/dist/{chunk-VXNMYUXU.js → chunk-57RRFUEZ.js} +23 -7
- package/dist/{chunk-WZ6YVQSF.js → chunk-7FTTULED.js} +1 -1
- package/dist/{chunk-ATSM5XAW.js → chunk-7XGFSUOM.js} +2 -2
- package/dist/chunk-CCS66K4K.js +155 -0
- package/dist/{chunk-I4WQAEYB.js → chunk-DVMLWQD4.js} +8 -186
- package/dist/{chunk-CZU3V3DQ.js → chunk-DX5CDO34.js} +27 -6
- package/dist/chunk-EQ255HKO.js +38248 -0
- package/dist/{chunk-BBEFP4SB.js → chunk-HBGADCKA.js} +3 -3
- package/dist/{chunk-QJQZH5GQ.js → chunk-HFGZGYCG.js} +10 -6
- package/dist/{chunk-ECBLHAZO.js → chunk-JOCDD4ON.js} +1 -1
- package/dist/{chunk-TKHSULJT.js → chunk-KPQY44JQ.js} +6 -0
- package/dist/{chunk-4P355ZWB.js → chunk-MAPZ7VB6.js} +21 -1
- package/dist/chunk-V2NUHPXF.js +196 -0
- package/dist/{chunk-RSG4ONOI.js → chunk-VYXXOKYS.js} +5 -5
- package/dist/{community-report-client-XXWGSBSD.js → community-report-client-CU22W53K.js} +1 -1
- package/dist/{config-EXUGQN5T.js → config-XO3LI3SA.js} +4 -4
- package/dist/context-IFJI3LIT.js +46 -0
- package/dist/{data-integration-4NZ53OMT.js → data-integration-HNGUKFIC.js} +44 -35
- package/dist/index.js +101 -64
- package/dist/{local-data-upload-client-KYOKVYZV.js → local-data-upload-client-GTRIT64F.js} +3 -2
- package/dist/{memory-ATNKZNW5.js → memory-QGPSNCQS.js} +4 -4
- package/dist/{metadata-VZVC7YMH.js → metadata-DI5BMYFU.js} +8 -8
- package/dist/{model-E4JMQ4V2.js → model-RNPQXIBI.js} +4 -4
- package/dist/{personal-semantic-preference-7S2SQ3UV.js → personal-semantic-preference-5C3WUXFI.js} +11 -8
- package/dist/{project-semantic-2SZP2OPO.js → project-semantic-3LF6Q6JZ.js} +27 -21
- package/dist/{sync-YV3E66IF.js → sync-O45NXEQY.js} +7 -6
- package/dist/{te-agent-JB5T3PO7.js → te-agent-K5MSPNHJ.js} +5 -5
- package/dist/{te-analysis-3YJAAT2D.js → te-analysis-AISWCOOZ.js} +1086 -354
- package/dist/{te-community-UDBI672N.js → te-community-4OYU3BDA.js} +4 -4
- package/dist/{te-dataops-ZLYOCXZ4.js → te-dataops-NFIPB6FX.js} +5 -5
- package/dist/{te-engage-4XG6OJML.js → te-engage-BAM3GBFX.js} +7 -7
- package/dist/{te-experiment-VXUWPINJ.js → te-experiment-GUTZXZ5Z.js} +132 -14
- package/dist/{te-kb-WYQWHFSC.js → te-kb-3TS73NO6.js} +454 -194
- package/dist/{te-system-7G6F2LJA.js → te-system-STMHLS5J.js} +12 -7
- package/dist/{te-team-E7FBBXMQ.js → te-team-3I5AOX3N.js} +6 -6
- package/dist/{update-D47BUG25.js → update-RZXLPCRH.js} +4 -4
- package/package.json +21 -14
- package/skills/ae-analysis/SKILL.md +91 -78
- package/skills/ae-analysis/references/adhoc_export.md +11 -18
- package/skills/ae-analysis/references/adhoc_run.md +15 -7
- package/skills/ae-analysis/references/agent_review_detail.md +11 -0
- package/skills/ae-analysis/references/agent_review_evidence.md +46 -0
- package/skills/ae-analysis/references/agent_review_list.md +9 -0
- package/skills/ae-analysis/references/agent_review_preflight.md +96 -0
- package/skills/ae-analysis/references/agent_review_priorities_comparisons.md +76 -0
- package/skills/ae-analysis/references/agent_review_records.md +9 -0
- package/skills/ae-analysis/references/agent_review_retry.md +12 -0
- package/skills/ae-analysis/references/agent_review_review.md +16 -0
- package/skills/ae-analysis/references/agent_review_submit_to_page.md +184 -0
- package/skills/ae-analysis/references/ai_models/attribution.md +29 -0
- package/skills/ae-analysis/references/ai_models/distribution.md +40 -0
- package/skills/ae-analysis/references/ai_models/event.md +108 -0
- package/skills/ae-analysis/references/ai_models/funnel.md +46 -0
- package/skills/ae-analysis/references/ai_models/heat_map.md +26 -0
- package/skills/ae-analysis/references/ai_models/interval.md +20 -0
- package/skills/ae-analysis/references/ai_models/path.md +38 -0
- package/skills/ae-analysis/references/ai_models/prop_analysis.md +39 -0
- package/skills/ae-analysis/references/ai_models/rank_list.md +25 -0
- package/skills/ae-analysis/references/ai_models/retention.md +70 -0
- package/skills/ae-analysis/references/ai_models/revenue.md +28 -0
- package/skills/ae-analysis/references/ai_models/sql.md +74 -0
- package/skills/ae-analysis/references/ai_models/tag.md +19 -0
- package/skills/ae-analysis/references/ai_models.md +32 -473
- package/skills/ae-analysis/references/alert_create.md +7 -7
- package/skills/ae-analysis/references/alert_delete.md +4 -6
- package/skills/ae-analysis/references/alert_detail_list.md +7 -9
- package/skills/ae-analysis/references/alert_get.md +5 -7
- package/skills/ae-analysis/references/alert_job_list.md +4 -6
- package/skills/ae-analysis/references/alert_list.md +6 -8
- package/skills/ae-analysis/references/alert_notice_config_list.md +4 -6
- package/skills/ae-analysis/references/alert_start.md +5 -7
- package/skills/ae-analysis/references/alert_stop.md +5 -7
- package/skills/ae-analysis/references/alert_update.md +8 -8
- package/skills/ae-analysis/references/analysis_data_export.md +72 -0
- package/skills/ae-analysis/references/analysis_data_retrieval.md +32 -196
- package/skills/ae-analysis/references/analysis_gateway_assets.md +23 -180
- package/skills/ae-analysis/references/analysis_interpretation.md +37 -17
- package/skills/ae-analysis/references/asset_abnormal_get.md +0 -1
- package/skills/ae-analysis/references/asset_abnormal_list.md +0 -1
- package/skills/ae-analysis/references/asset_authentication_export.md +4 -0
- package/skills/ae-analysis/references/asset_authentication_list.md +7 -1
- package/skills/ae-analysis/references/asset_authentication_update.md +5 -1
- package/skills/ae-analysis/references/asset_batch_dashboard_schedule_freeze.md +8 -6
- package/skills/ae-analysis/references/asset_batch_delete.md +6 -6
- package/skills/ae-analysis/references/asset_batch_disable_auto_backup.md +4 -5
- package/skills/ae-analysis/references/asset_batch_disable_auto_update.md +5 -6
- package/skills/ae-analysis/references/asset_batch_handover.md +4 -5
- package/skills/ae-analysis/references/asset_batch_info_export.md +4 -5
- package/skills/ae-analysis/references/asset_batch_sql_export.md +5 -6
- package/skills/ae-analysis/references/asset_dependency_list.md +4 -5
- package/skills/ae-analysis/references/asset_export.md +4 -5
- package/skills/ae-analysis/references/asset_impact_list.md +5 -9
- package/skills/ae-analysis/references/asset_lineage_get.md +5 -6
- package/skills/ae-analysis/references/asset_list.md +4 -5
- package/skills/ae-analysis/references/asset_query_history_list.md +4 -8
- package/skills/ae-analysis/references/asset_recent_list.md +0 -1
- package/skills/ae-analysis/references/asset_search.md +12 -9
- package/skills/ae-analysis/references/asset_url_get.md +3 -4
- package/skills/ae-analysis/references/bi_panel_copy.md +2 -2
- package/skills/ae-analysis/references/bi_panel_page_data_export.md +4 -12
- package/skills/ae-analysis/references/bi_panel_page_data_run.md +2 -0
- package/skills/ae-analysis/references/catalog_export.md +4 -17
- package/skills/ae-analysis/references/catalog_list.md +4 -4
- package/skills/ae-analysis/references/check_delete.md +5 -7
- package/skills/ae-analysis/references/check_export.md +11 -11
- package/skills/ae-analysis/references/check_get.md +8 -10
- package/skills/ae-analysis/references/check_list.md +4 -6
- package/skills/ae-analysis/references/check_retry.md +8 -10
- package/skills/ae-analysis/references/check_run.md +2 -4
- package/skills/ae-analysis/references/command_index.md +44 -26
- package/skills/ae-analysis/references/dashboard_report_data_export.md +5 -13
- package/skills/ae-analysis/references/dashboard_report_data_run.md +1 -1
- package/skills/ae-analysis/references/dashboard_update.md +14 -3
- package/skills/ae-analysis/references/datatable_columns_get.md +0 -1
- package/skills/ae-analysis/references/datatable_influence_list.md +0 -1
- package/skills/ae-analysis/references/datatable_version_get.md +0 -1
- package/skills/ae-analysis/references/datatable_version_list.md +0 -1
- package/skills/ae-analysis/references/debug_device_add.md +1 -2
- package/skills/ae-analysis/references/drilldown_entities_export.md +3 -3
- package/skills/ae-analysis/references/drilldown_events_export.md +3 -2
- package/skills/ae-analysis/references/drilldown_user_events_export.md +2 -2
- package/skills/ae-analysis/references/entity_detail_export.md +3 -2
- package/skills/ae-analysis/references/entity_detail_run.md +1 -0
- package/skills/ae-analysis/references/event_blacklist_add.md +5 -7
- package/skills/ae-analysis/references/event_blacklist_list.md +4 -6
- package/skills/ae-analysis/references/event_blacklist_update.md +6 -8
- package/skills/ae-analysis/references/event_changelog_list.md +0 -1
- package/skills/ae-analysis/references/event_create.md +0 -1
- package/skills/ae-analysis/references/event_detail_export.md +3 -2
- package/skills/ae-analysis/references/event_detail_run.md +1 -0
- package/skills/ae-analysis/references/event_export.md +0 -1
- package/skills/ae-analysis/references/event_get.md +0 -1
- package/skills/ae-analysis/references/event_hide_update.md +0 -1
- package/skills/ae-analysis/references/event_influence_list.md +0 -1
- package/skills/ae-analysis/references/event_list.md +0 -1
- package/skills/ae-analysis/references/event_property_bundle_export.md +5 -14
- package/skills/ae-analysis/references/event_property_bundle_import.md +2 -6
- package/skills/ae-analysis/references/event_relation_update.md +0 -1
- package/skills/ae-analysis/references/event_update.md +0 -1
- package/skills/ae-analysis/references/exchange_config_update.md +0 -1
- package/skills/ae-analysis/references/exchange_rate_refresh.md +0 -1
- package/skills/ae-analysis/references/exchange_rule_list.md +0 -1
- package/skills/ae-analysis/references/exchange_rule_update.md +0 -1
- package/skills/ae-analysis/references/exchange_rule_validate.md +0 -1
- package/skills/ae-analysis/references/governance_recommendation_decisions.md +23 -0
- package/skills/ae-analysis/references/governance_recommendation_export.md +108 -0
- package/skills/ae-analysis/references/governance_recommendation_submit.md +41 -0
- package/skills/ae-analysis/references/history_tag_data_drilldown_export.md +4 -4
- package/skills/ae-analysis/references/history_tag_data_export.md +3 -3
- package/skills/ae-analysis/references/ingest_error_list.md +7 -9
- package/skills/ae-analysis/references/ingest_summary.md +6 -8
- package/skills/ae-analysis/references/live_data_export.md +10 -10
- package/skills/ae-analysis/references/live_data_list.md +7 -9
- package/skills/ae-analysis/references/metadata_resolution.md +78 -0
- package/skills/ae-analysis/references/metric_export.md +0 -1
- package/skills/ae-analysis/references/metric_get.md +0 -1
- package/skills/ae-analysis/references/metric_list.md +4 -5
- package/skills/ae-analysis/references/metric_update.md +0 -1
- package/skills/ae-analysis/references/operation_record_export.md +4 -5
- package/skills/ae-analysis/references/operation_record_list.md +4 -5
- package/skills/ae-analysis/references/personal_semantic_preference_list.md +18 -1
- package/skills/ae-analysis/references/plan_change_log_export.md +10 -10
- package/skills/ae-analysis/references/plan_change_log_list.md +4 -6
- package/skills/ae-analysis/references/plan_delete_items.md +2 -4
- package/skills/ae-analysis/references/plan_export.md +9 -9
- package/skills/ae-analysis/references/plan_generate.md +2 -4
- package/skills/ae-analysis/references/plan_get.md +4 -6
- package/skills/ae-analysis/references/plan_import_excel.md +6 -8
- package/skills/ae-analysis/references/plan_save_items.md +2 -4
- package/skills/ae-analysis/references/plan_sync_from_meta.md +4 -6
- package/skills/ae-analysis/references/project_access_detail_get.md +0 -1
- package/skills/ae-analysis/references/project_data_power_get.md +0 -1
- package/skills/ae-analysis/references/project_data_power_list.md +0 -1
- package/skills/ae-analysis/references/project_data_power_upsert.md +0 -1
- package/skills/ae-analysis/references/project_entity_create.md +0 -1
- package/skills/ae-analysis/references/project_entity_event_list.md +0 -1
- package/skills/ae-analysis/references/project_entity_get.md +0 -1
- package/skills/ae-analysis/references/project_entity_list.md +0 -1
- package/skills/ae-analysis/references/project_entity_update.md +0 -1
- package/skills/ae-analysis/references/project_function_list.md +0 -1
- package/skills/ae-analysis/references/project_info_get.md +0 -1
- package/skills/ae-analysis/references/project_info_list.md +0 -1
- package/skills/ae-analysis/references/project_info_update.md +0 -1
- package/skills/ae-analysis/references/project_mark_time_create.md +0 -1
- package/skills/ae-analysis/references/project_mark_time_list.md +0 -1
- package/skills/ae-analysis/references/project_mark_time_update.md +0 -1
- package/skills/ae-analysis/references/project_member_add.md +6 -5
- package/skills/ae-analysis/references/project_member_batch_update.md +0 -1
- package/skills/ae-analysis/references/project_member_candidate_list.md +4 -3
- package/skills/ae-analysis/references/project_member_handover_run.md +2 -3
- package/skills/ae-analysis/references/project_member_list.md +0 -1
- package/skills/ae-analysis/references/project_member_receiver_list.md +0 -1
- package/skills/ae-analysis/references/project_member_update.md +0 -1
- package/skills/ae-analysis/references/project_owner_update.md +0 -1
- package/skills/ae-analysis/references/project_permission_binding_list.md +0 -1
- package/skills/ae-analysis/references/project_role_function_list.md +0 -1
- package/skills/ae-analysis/references/project_role_get.md +0 -1
- package/skills/ae-analysis/references/project_role_list.md +0 -1
- package/skills/ae-analysis/references/project_role_upsert.md +32 -2
- package/skills/ae-analysis/references/project_role_user_list.md +0 -1
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +214 -0
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +93 -0
- package/skills/ae-analysis/references/project_timezone_get.md +0 -1
- package/skills/ae-analysis/references/project_timezone_overview.md +0 -1
- package/skills/ae-analysis/references/project_timezone_update.md +0 -1
- package/skills/ae-analysis/references/project_user_id_items_update.md +0 -1
- package/skills/ae-analysis/references/property_changelog_list.md +0 -1
- package/skills/ae-analysis/references/property_create.md +0 -1
- package/skills/ae-analysis/references/property_export.md +0 -1
- package/skills/ae-analysis/references/property_get.md +0 -1
- package/skills/ae-analysis/references/property_hide_update.md +0 -1
- package/skills/ae-analysis/references/property_influence_list.md +0 -1
- package/skills/ae-analysis/references/property_list.md +3 -4
- package/skills/ae-analysis/references/property_related_events.md +0 -1
- package/skills/ae-analysis/references/property_relation_update.md +0 -1
- package/skills/ae-analysis/references/property_update.md +0 -1
- package/skills/ae-analysis/references/report_create.md +4 -2
- package/skills/ae-analysis/references/report_data_export.md +11 -9
- package/skills/ae-analysis/references/report_data_run.md +14 -7
- package/skills/ae-analysis/references/report_get.md +5 -3
- package/skills/ae-analysis/references/report_list.md +2 -0
- package/skills/ae-analysis/references/report_update.md +5 -3
- package/skills/ae-analysis/references/rule_create.md +5 -6
- package/skills/ae-analysis/references/rule_delete.md +5 -5
- package/skills/ae-analysis/references/rule_list.md +3 -4
- package/skills/ae-analysis/references/rule_schema.md +3 -4
- package/skills/ae-analysis/references/rule_update.md +5 -6
- package/skills/ae-analysis/references/sdk_sample_generate.md +2 -4
- package/skills/ae-analysis/references/sql_table_columns.md +1 -1
- package/skills/ae-analysis/references/super_metadata_batch_create.md +1 -1
- package/skills/ae-analysis/references/super_metadata_batch_edit.md +1 -1
- package/skills/ae-analysis/references/system_member_add.md +1 -2
- package/skills/ae-analysis/references/system_member_status_update.md +1 -1
- package/skills/ae-analysis/references/system_ops_alert_contact_list.md +1 -1
- package/skills/ae-analysis/references/system_ops_alert_contact_test.md +0 -1
- package/skills/ae-analysis/references/system_query_monitor_overview.md +3 -3
- package/skills/ae-analysis/references/system_query_task_export.md +4 -14
- package/skills/ae-analysis/references/system_query_task_get.md +1 -1
- package/skills/ae-analysis/references/system_query_task_list.md +5 -6
- package/skills/ae-analysis/references/system_receiver_address_upsert.md +3 -3
- package/skills/ae-analysis/references/system_receiver_detection_get.md +1 -1
- package/skills/ae-analysis/references/system_third_party_login_disable.md +1 -1
- package/skills/ae-analysis/references/system_usage_trend_export.md +3 -12
- package/skills/ae-analysis/references/user_cluster_list.md +1 -1
- package/skills/ae-analysis/references/user_cluster_member_export.md +4 -4
- package/skills/ae-analysis/references/user_tag_list.md +1 -1
- package/skills/ae-analysis/references/user_tag_member_export.md +4 -4
- package/skills/ae-analysis/references/virtual_event_create.md +10 -5
- package/skills/ae-analysis/references/virtual_event_get.md +0 -1
- package/skills/ae-analysis/references/virtual_property_create.md +0 -1
- package/skills/ae-analysis/references/virtual_property_sql_rule_update.md +0 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +1054 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +112 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +30 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +2735 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +376 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/plan-kb-source-sync.mjs +264 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/precompiled-source.mjs +49 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/upload-kb-sources-concurrently.mjs +200 -0
- package/skills/ae-analysis/scripts/read_results.py +197 -0
- package/skills/ae-analysis-global/SKILL.md +1 -1
- package/skills/ae-capability/SKILL.md +1 -1
- package/skills/ae-community/SKILL.md +1 -1
- package/skills/ae-current-context/SKILL.md +53 -0
- package/skills/ae-data-integration/SKILL.md +5 -4
- package/skills/ae-data-integration/references/lark-bitable-source.md +288 -0
- package/skills/ae-data-integration/references/lark-sheet-source.md +130 -0
- package/skills/ae-data-integration/references/manual-export-source.md +83 -0
- package/skills/ae-data-integration/references/reuse.md +2 -0
- package/skills/ae-data-integration/references/sink-upload.md +32 -0
- package/skills/ae-data-integration/references/tracking-plan.md +4 -1
- package/skills/ae-data-integration/references/ue-mapping.md +2 -2
- package/skills/ae-data-integration-helper/SKILL.md +5 -5
- package/skills/ae-data-integration-helper/references/android_sdk_faq.md +3 -3
- package/skills/ae-data-integration-helper/references/c_sdk_faq.md +3 -3
- package/skills/ae-data-integration-helper/references/cocoscreator_sdk_faq.md +1 -1
- package/skills/ae-data-integration-helper/references/cpp_server_sdk_faq.md +3 -3
- package/skills/ae-data-integration-helper/references/ios_sdk_faq.md +1 -1
- package/skills/ae-data-integration-helper/references/java_sdk_faq.md +3 -3
- package/skills/ae-data-integration-helper/references/javascript_sdk_faq.md +1 -1
- package/skills/ae-data-integration-helper/references/logbus2_guide.md +1 -1
- package/skills/ae-data-integration-helper/references/logbus2_parser_plugin.md +2 -2
- package/skills/ae-data-integration-helper/references/minigame_sdk_faq.md +2 -2
- package/skills/ae-data-integration-helper/references/miniprogram_sdk_faq.md +1 -1
- package/skills/ae-data-integration-helper/references/python_sdk_faq.md +2 -2
- package/skills/ae-data-integration-helper/references/restful_api_notes.md +2 -2
- package/skills/ae-data-integration-helper/references/sdk_log_guide.md +3 -3
- package/skills/ae-data-integration-helper/references/sdk_usage_notes.md +11 -11
- package/skills/ae-data-integration-helper/references/unity_sdk_faq.md +1 -1
- package/skills/ae-dataops/SKILL.md +1 -1
- package/skills/ae-engage/SKILL.md +4 -3
- package/skills/ae-engage/references/build-task-save-guide.md +3 -0
- package/skills/ae-engage/references/flow-metric-update.md +115 -1
- package/skills/ae-engage/references/save-flow.md +3 -0
- package/skills/ae-engage/references/save-task.md +21 -0
- package/skills/ae-engage/references/task-metric-update.md +151 -0
- package/skills/ae-experiment/SKILL.md +14 -7
- package/skills/ae-experiment/references/save_submit_external_experiment.md +52 -0
- package/skills/ae-experiment-design/SKILL.md +3 -3
- package/skills/ae-experiment-design/references/platform-operations.md +1 -1
- package/skills/ae-experiment-insight/SKILL.md +2 -2
- package/skills/ae-experiment-insight/references/platform-operations.md +1 -1
- package/skills/ae-generate-tracking-code/SKILL.md +2 -1
- package/skills/ae-generate-tracking-code/references/client-sdk-insert.md +1 -1
- package/skills/ae-generate-tracking-code/references/datax-config.md +1 -1
- package/skills/ae-generate-tracking-code/references/logbus-config.md +1 -1
- package/skills/ae-generate-tracking-code/references/modes.md +1 -1
- package/skills/ae-generate-tracking-code/references/server-sdk-insert.md +5 -5
- package/skills/ae-generate-tracking-code/references/snippet-delivery.md +3 -3
- package/skills/ae-generate-tracking-plan/SKILL.md +2 -2
- package/skills/ae-generate-tracking-plan/references/te-api.md +1 -0
- package/skills/ae-generate-tracking-plan/references/xlsx-schema.md +3 -2
- package/skills/ae-kb/SKILL.md +41 -2
- package/skills/ae-kb/references/analysis-workflow.md +292 -0
- package/skills/ae-kb/references/source-mutations.md +95 -0
- package/skills/ae-kb-discovery/SKILL.md +5 -1
- package/skills/ae-metadata/SKILL.md +1 -1
- package/skills/ae-migrate-tracking-code/SKILL.md +195 -0
- package/skills/ae-migrate-tracking-code/references/ae-preset-properties.md +76 -0
- package/skills/ae-migrate-tracking-code/references/ir.md +167 -0
- package/skills/ae-migrate-tracking-code/references/mapping-framework.md +112 -0
- package/skills/ae-migrate-tracking-code/references/providers/README.md +58 -0
- package/skills/ae-migrate-tracking-code/references/providers/amplitude.md +208 -0
- package/skills/ae-migrate-tracking-code/references/providers/firebase.md +160 -0
- package/skills/ae-migrate-tracking-code/references/providers/ga4.md +92 -0
- package/skills/ae-migrate-tracking-code/references/providers/mixpanel.md +150 -0
- package/skills/ae-migrate-tracking-code/references/providers/sensors-data.md +146 -0
- package/skills/ae-project-semantic/SKILL.md +1 -1
- package/skills/ae-system/SKILL.md +4 -4
- package/skills/ae-team/SKILL.md +2 -2
- package/skills/ae-use-agent/references/local-agent.md +1 -1
- package/dist/chunk-TAL6CZH6.js +0 -72
- 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 |
|
|
@@ -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):
|
|
@@ -12,7 +12,10 @@ Generate and confirm the event/property plan **before** any transform or upload.
|
|
|
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
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
|
|
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
|
|
|
@@ -74,7 +74,7 @@ Each mapped system field carries a value spec, enforced at both inspect (warning
|
|
|
74
74
|
|
|
75
75
|
Event-name case is decided entirely by the mapping, never by the CLI — the CLI performs no case conversion and has no flag for it. The name AE receives is the source `event_name_field` value (or `default_event_name` when there is no event column), optionally replaced by a `value_mapping.event_name` target; `data-integration plan --event-name` passes each name through unchanged. Lowercase is the default: lowercase the name when writing the mapping (a `value_mapping.event_name` entry such as `Purchase` → `purchase`, or a lowercase `default_event_name`). To keep uppercase, skip that lowercasing: leave a legal uppercase source value unmapped so it passes through, write an uppercase `value_mapping.event_name` target only when the source value is not itself a legal name (e.g. `购买` → `Purchase`), or write an uppercase `default_event_name` / `--event-name`.
|
|
76
76
|
|
|
77
|
-
A field skip is not a row failure: the row is kept with its other fields, and the count is reported in `manifest.output.skipped_fields` so the agent tells the user at the end. `#uuid` is never auto-generated — it comes only from a mapped source column.
|
|
77
|
+
A field skip is not a row failure: the row is kept with its other fields, and the count is reported in `manifest.output.skipped_fields` so the agent tells the user at the end. `#uuid` is never auto-generated — it comes only from a mapped source column. `#uuid` accepts only a valid 36-character UUID; any other value (a business order/event id, a numeric id) is skipped from that row (`skipped_fields`), never emitted. So propose `uuid_field` only when the source has a column that already holds valid UUIDs — a `#uuid` gives the receiver a dedup key, so a re-submitted record is de-duplicated instead of creating a true duplicate, while without `#uuid` every re-submission appends a real duplicate. Never fabricate UUIDs, and never map a non-UUID unique key to `uuid_field`: the CLI validates the format but does not convert, synthesize, or de-duplicate values.
|
|
78
78
|
|
|
79
79
|
Mapping keys: `account_id_field`, `distinct_id_field`, `time.field`, `event_name_field` (or a reviewed `default_event_name`), `ip_field`, `uuid_field`. Inspect surfaces every identity-shaped column in `identity_candidates` (name, `account`/`distinct` kind, unique and missing ratios) so the agent can present all candidates for confirmation. When the required identity column is absent, use an explicit `account_id_value`/`distinct_id_value` placeholder or `random_pool` — a user decision, never invented.
|
|
80
80
|
|
|
@@ -138,7 +138,7 @@ Values with an explicit offset or `Z` are parsed by the JavaScript `Date` constr
|
|
|
138
138
|
## Data rules
|
|
139
139
|
|
|
140
140
|
- **Ingestion time window.** The receiver accepts event/profile times from 3 years before to 3 days after the server time; the CLI enforces this range. Client-side reporting has a tighter window (10 days before to 3 days after); historical data beyond the window needs AE support to extend it.
|
|
141
|
-
- **Property type locking.** A property's type is locked on first receipt, and properties sharing a name across events are one property — later reports must use the same type. Values whose type mismatches the locked type are dropped silently, so review an inferred type before committing it.
|
|
141
|
+
- **Property type locking.** A property's type is locked on first receipt, and properties sharing a name across events are one property — later reports must use the same type. Values whose type mismatches the locked type are dropped silently, so review an inferred type before committing it — and before that, check the project's **already-locked** types with `ae-cli analysis-meta property list -p <project-id> --table-type user` / `--table-type event`, diffing each target property name against `select_type` (see tracking-plan.md step 4). The plan layer may still say `string` while the runtime layer has locked `number`; only the runtime `select_type` gates ingestion.
|
|
142
142
|
- **Quote stripping.** Paired single or double quotes around a cell value are stripped (`'user_001'` → `user_001`); a single-sided quote is kept as data (SQL exports often quote every value).
|
|
143
143
|
- **Column name sanitization.** Recommended mapping auto-names properties: accents are stripped, camelCase is split to snake_case, everything is lowercased, and illegal characters become `_`; a digit-leading name is prefixed `field_`, and a name with nothing recognizable falls back to `field_N`. Review these targets — especially the `field_N` fallbacks — and rename before converting.
|
|
144
144
|
- **Object sub-property keys.** Object and list-of-object keys follow the same naming rules as property names (lowercase snake_case, letter-leading, at most 50 chars, no `#`). A key that does not — for example a Chinese key inside a JSON cell such as `{"等级":"金牌"}` — quarantines the whole row, so confirm object keys before converting.
|