@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.
- package/README.md +96 -38
- package/README.zh.md +96 -38
- package/dist/{auth-QPEVVBKT.js → auth-XZNXFRJS.js} +236 -127
- package/dist/{capability-ASI62I4A.js → capability-FYTU3X6L.js} +80 -37
- package/dist/{chunk-QL6R6TSK.js → chunk-4NRCTUZJ.js} +27045 -477
- package/dist/{chunk-JYMGHGCE.js → chunk-57RRFUEZ.js} +42 -15
- package/dist/chunk-6ZIQV5GW.js +26 -0
- package/dist/{chunk-KZ6ZHF5J.js → chunk-7FTTULED.js} +14 -14
- package/dist/chunk-7XGFSUOM.js +623 -0
- package/dist/chunk-CCS66K4K.js +155 -0
- package/dist/{chunk-B5HMQAOM.js → chunk-DVMLWQD4.js} +8 -186
- package/dist/{chunk-KEWVSO64.js → chunk-DX5CDO34.js} +28 -18
- package/dist/chunk-EQ255HKO.js +38248 -0
- package/dist/{chunk-6QK7SYYY.js → chunk-HBGADCKA.js} +29 -37
- package/dist/{chunk-GJXRF7Y6.js → chunk-HFGZGYCG.js} +54 -81
- package/dist/chunk-JOCDD4ON.js +15 -0
- package/dist/{chunk-TKHSULJT.js → chunk-KPQY44JQ.js} +6 -0
- package/dist/{chunk-FR2EDAQM.js → chunk-MAPZ7VB6.js} +90 -2
- package/dist/chunk-V2NUHPXF.js +196 -0
- package/dist/{chunk-S5PONFBM.js → chunk-VYXXOKYS.js} +9 -9
- package/dist/{community-report-client-6OL6GBQW.js → community-report-client-CU22W53K.js} +2 -4
- package/dist/{config-XNMACCKX.js → config-XO3LI3SA.js} +8 -9
- package/dist/context-IFJI3LIT.js +46 -0
- package/dist/{data-integration-4NZGZ45E.js → data-integration-HNGUKFIC.js} +55 -44
- package/dist/index.js +122 -112
- package/dist/{local-data-upload-client-EFHDLXFG.js → local-data-upload-client-GTRIT64F.js} +4 -5
- package/dist/{memory-HBJQ2GC5.js → memory-QGPSNCQS.js} +4 -6
- package/dist/{metadata-62EWBEIG.js → metadata-DI5BMYFU.js} +8 -10
- package/dist/{model-BHLJ2QMT.js → model-RNPQXIBI.js} +4 -6
- package/dist/{personal-semantic-preference-JBVMAI7L.js → personal-semantic-preference-5C3WUXFI.js} +11 -10
- package/dist/{project-semantic-BQ4MPUS5.js → project-semantic-3LF6Q6JZ.js} +29 -25
- package/dist/{sync-MUWPRM5I.js → sync-O45NXEQY.js} +7 -8
- package/dist/{te-agent-WQZTMEK4.js → te-agent-K5MSPNHJ.js} +393 -90
- package/dist/{te-analysis-MNCG65LU.js → te-analysis-AISWCOOZ.js} +1175 -377
- package/dist/{te-community-BNE6KREL.js → te-community-4OYU3BDA.js} +10 -33
- package/dist/{te-dataops-TXLKM2W6.js → te-dataops-NFIPB6FX.js} +19 -20
- package/dist/{te-engage-TPKLRVTL.js → te-engage-BAM3GBFX.js} +13 -15
- package/dist/{te-experiment-6BYKTCY7.js → te-experiment-GUTZXZ5Z.js} +132 -16
- package/dist/te-kb-3TS73NO6.js +1992 -0
- package/dist/{te-system-44LZJDTQ.js → te-system-STMHLS5J.js} +12 -9
- package/dist/{te-team-XMP47YXE.js → te-team-3I5AOX3N.js} +6 -8
- package/dist/{update-UODFOZ4P.js → update-RZXLPCRH.js} +7 -8
- package/package.json +29 -19
- package/skills/ae-agent/SKILL.md +30 -13
- package/skills/ae-agent/references/agent-distribution.md +94 -0
- package/skills/ae-agent/references/approval-request.md +4 -0
- package/skills/ae-agent/references/command_index.md +9 -2
- package/skills/ae-agent/references/create-automation.md +20 -2
- package/skills/ae-agent/references/get-agent-context.md +70 -0
- package/skills/ae-agent/references/list-automations.md +18 -3
- package/skills/ae-agent/references/list-mcp-credentials.md +1 -1
- package/skills/ae-agent/references/mcp-token.md +3 -3
- package/skills/ae-agent/references/set-mcp-credential.md +0 -1
- package/skills/ae-agent/references/update-automation.md +18 -0
- package/skills/ae-analysis/SKILL.md +101 -79
- package/skills/ae-analysis/references/adhoc_export.md +11 -18
- package/skills/ae-analysis/references/adhoc_run.md +17 -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 -453
- 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 +46 -28
- package/skills/ae-analysis/references/cross_source_config.md +84 -0
- 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 +15 -4
- 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_create.md +23 -1
- 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/user_tag_models.md +9 -1
- package/skills/ae-analysis/references/user_tag_update.md +14 -2
- 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 +6 -4
- package/skills/ae-data-integration/references/dimension-routing.md +36 -0
- 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/local-analysis.md +2 -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/source-inspect.md +1 -1
- package/skills/ae-data-integration/references/tracking-plan.md +5 -2
- package/skills/ae-data-integration/references/transform.md +1 -1
- package/skills/ae-data-integration/references/ue-mapping.md +7 -4
- package/skills/ae-data-integration/references/ue-routing.md +17 -1
- 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 +27 -15
- package/skills/ae-generate-tracking-plan/references/business-dimension-mapping.md +1 -1
- 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 +147 -37
- package/skills/ae-kb/references/analysis-workflow.md +292 -0
- package/skills/ae-kb/references/query-workflow.md +59 -29
- package/skills/ae-kb/references/source-mutations.md +95 -0
- package/skills/ae-kb/references/versions.md +46 -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 +5 -5
- package/skills/ae-team/SKILL.md +2 -2
- package/skills/ae-use-agent/SKILL.md +42 -0
- package/skills/ae-use-agent/references/local-agent.md +114 -0
- package/dist/auth-UMJAA72O.js +0 -15
- package/dist/chunk-533JK3YX.js +0 -72
- package/dist/chunk-DKEXH6Q5.js +0 -72
- package/dist/chunk-O6K2ODUE.js +0 -318
- package/dist/chunk-RWXIXOZG.js +0 -326
- package/dist/client-N7NGZUNI.js +0 -204
- package/dist/te-kb-BUD6N3NI.js +0 -1222
- package/skills/ae-agent/references/auto-provision-mcp-credentials.md +0 -57
- 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
|
|
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
|
|
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,
|
|
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
|
|