| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| /// The valid dash tool labels stored in the [DashTool] enum. | |
| List<String> get validDashTools => | |
| DashTool.values.map((e) => e.label).toList()..sort(); | |
| /// Environment variables used by the unified analytics package. | |
| enum DashEnvVar { | |
| /// Environment variable used to suppress analytics. | |
| suppressAnalytics('DASH__SUPPRESS_ANALYTICS'), | |
| /// Environment variable used to specify the top-level tool. | |
| tool('DASH__TOOL'); | |
| final String name; | |
| const DashEnvVar(this.name); | |
| } | |
| /// Values for the event name to be sent to Google Analytics. | |
| /// | |
| /// The [label] for each enum value is what will be logged, the [description] | |
| /// is here for documentation purposes. | |
| /// | |
| /// Set the nullable [toolOwner] parameter if the event belongs to one specific | |
| /// tool, otherwise, if multiple tools will be sending the event, leave it null. | |
| enum DashEvent { | |
| // Events that can be sent by all tools; these | |
| // events should not be tool specific; toolOwner | |
| // not necessary for these events | |
| analyticsCollectionEnabled( | |
| label: 'analytics_collection_enabled', | |
| description: 'The opt-in status for analytics collection', | |
| ), | |
| analyticsException( | |
| label: 'analytics_exception', | |
| description: 'Errors that are encountered within package:unified_analytics', | |
| ), | |
| exception(label: 'exception', description: 'General errors to log'), | |
| surveyAction( | |
| label: 'survey_action', | |
| description: 'Actions taken by users when shown survey', | |
| ), | |
| surveyShown(label: 'survey_shown', description: 'Survey shown to the user'), | |
| timing( | |
| label: 'timing', | |
| description: 'Events for timing how long a process takes', | |
| ), | |
| // Events for the Dart CLI | |
| dartCliCommandExecuted( | |
| label: 'dart_cli_command_executed', | |
| description: 'Information about the execution of a Dart CLI command', | |
| toolOwner: DashTool.dartTool, | |
| ), | |
| pubGet( | |
| label: 'pub_get', | |
| description: 'Pub package resolution details', | |
| toolOwner: DashTool.dartTool, | |
| ), | |
| dartMCPEvent( | |
| label: 'dart_mcp_server', | |
| description: 'Information for a Dart MCP server event', | |
| toolOwner: DashTool.dartTool, | |
| ), | |
| packageSkillsEvent( | |
| label: 'package_skills', | |
| description: 'Information for a package:skills event', | |
| ), | |
| // Events for Flutter devtools | |
| devtoolsEvent( | |
| label: 'devtools_event', | |
| description: 'Information for various devtools events', | |
| toolOwner: DashTool.devtools, | |
| ), | |
| // Events for the Flutter CLI | |
| appleUsageEvent( | |
| label: 'apple_usage_event', | |
| description: | |
| 'Events related to iOS/macOS workflows within the flutter tool', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| codeSizeAnalysis( | |
| label: 'code_size_analysis', | |
| description: 'Indicates when the "--analyze-size" command is run', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| commandUsageValues( | |
| label: 'command_usage_values', | |
| description: | |
| 'Contains command level custom dimensions from legacy ' | |
| 'flutter analytics', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| doctorValidatorResult( | |
| label: 'doctor_validator_result', | |
| description: 'Results from a specific doctor validator', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| flutterBuildInfo( | |
| label: 'flutter_build_info', | |
| description: 'Information for a flutter build invocation', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| flutterCommandResult( | |
| label: 'flutter_command_result', | |
| description: 'Provides information about flutter commands that ran', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| @Deprecated( | |
| "Use 'flutterWasmDryRunPackage' instead. This will be removed in " | |
| 'a future version.', | |
| ) | |
| flutterWasmDryRun( | |
| label: 'wasm_dry_run', | |
| description: 'Information for a dart2wasm dry run invoked from Flutter', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| flutterWasmDryRunPackage( | |
| label: 'wasm_dry_run_package', | |
| description: | |
| 'Information for a dart2wasm dry run invoked from Flutter with package ' | |
| 'info', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| flutterInjectDarwinPlugins( | |
| label: 'flutter_inject_darwin_plugins', | |
| description: 'Information on plugins injected into an iOS/macOS project', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| flutterTrackAndroidDependencies( | |
| label: 'flutter_android_dependencies', | |
| description: | |
| 'Information related to min/target/compile SDK, JDK, NDK, Gradle version', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| hotReloadTime( | |
| label: 'hot_reload_time', | |
| description: 'Hot reload duration', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| hotRunnerInfo( | |
| label: 'hot_runner_info', | |
| description: 'Information related to the Flutter hot runner', | |
| toolOwner: DashTool.flutterTool, | |
| ), | |
| // Events for IDEs (intellij and vscode) | |
| ideEvent( | |
| label: 'ide_event', | |
| description: 'Information for various IDE events', | |
| ), | |
| // Events for language_server below | |
| analysisStatistics( | |
| label: 'analysis_statistics', | |
| description: 'Dart analyzer statistics', | |
| ), | |
| clientNotification( | |
| label: 'client_notification', | |
| description: 'Notifications sent from the client', | |
| ), | |
| clientRequest( | |
| label: 'client_request', | |
| description: 'Requests sent from the client', | |
| ), | |
| commandExecuted( | |
| label: 'command_executed', | |
| description: 'Number of times a command is executed', | |
| ), | |
| contextStructure( | |
| label: 'context_structure', | |
| description: 'Structure of the analysis contexts being analyzed', | |
| ), | |
| lintUsageCount( | |
| label: 'lint_usage_count', | |
| description: 'Number of times a given lint is enabled', | |
| ), | |
| memoryInfo(label: 'memory_info', description: 'Memory usage information'), | |
| pluginRequest( | |
| label: 'plugin_request', | |
| description: | |
| 'Analyzer plugin performance information regarding server requests', | |
| ), | |
| plugins( | |
| label: 'plugins', | |
| description: 'Information about how often _new_ analyzer plugins were used', | |
| ), | |
| pluginUse( | |
| label: 'plugin_use', | |
| description: | |
| 'Information about how often a _legacy_ analyzer plugin was used', | |
| ), | |
| serverSession( | |
| label: 'server_session', | |
| description: 'Dart Analyzer Server session data', | |
| ), | |
| severityAdjustment( | |
| label: 'severity_adjustment', | |
| description: 'Number of times diagnostic severity is changed', | |
| ); | |
| final String label; | |
| final String description; | |
| final DashTool? toolOwner; | |
| const DashEvent({ | |
| required this.label, | |
| required this.description, | |
| this.toolOwner, | |
| }); | |
| /// This takes in the string label for a given [DashEvent] and returns the | |
| /// enum for that string label. | |
| static DashEvent? fromLabel(String label) => | |
| DashEvent.values.where((e) => e.label == label).firstOrNull; | |
| } | |
| /// Officially-supported clients of this package as logical | |
| /// tools, grouped by user point of view. Derived directly | |
| /// from the PDD. | |
| enum DashTool { | |
| androidStudioPlugins( | |
| label: 'android-studio-plugins', | |
| description: 'Android Studio IDE plugins for Dart and Flutter', | |
| ), | |
| dartTool(label: 'dart-tool', description: 'Dart CLI developer tool'), | |
| devtools( | |
| label: 'devtools', | |
| description: 'DevTools debugging and performance tools', | |
| ), | |
| flutterTool(label: 'flutter-tool', description: 'Flutter CLI developer tool'), | |
| intellijPlugins( | |
| label: 'intellij-plugins', | |
| description: 'IntelliJ IDE plugins for Dart and Flutter', | |
| ), | |
| vscodePlugins( | |
| label: 'vscode-plugins', | |
| description: 'VS Code IDE extensions for Dart and Flutter', | |
| ); | |
| /// String used as the control flag and the value of the tool key in | |
| /// analytics. | |
| final String label; | |
| /// The "notice string", a human-readable description of the logical tool | |
| /// grouping. | |
| final String description; | |
| const DashTool({required this.label, required this.description}); | |
| /// This takes in the string label for a given [DashTool] and returns the | |
| /// enum for that string label. | |
| static DashTool fromLabel(String label) { | |
| final tool = DashTool.values.where((t) => t.label == label).firstOrNull; | |
| if (tool != null) return tool; | |
| throw Exception( | |
| 'The tool $label from the survey metadata file is not ' | |
| 'a valid DashTool enum value\n' | |
| 'Valid labels for dash tools: ${validDashTools.join(', ')}', | |
| ); | |
| } | |
| } | |
| /// Enumerate options for platforms supported. | |
| enum DevicePlatform { | |
| windows('Windows'), | |
| macos('macOS'), | |
| linux('Linux'); | |
| final String label; | |
| const DevicePlatform(this.label); | |
| } | |
| /// Enumerate options for AI agents supported. | |
| enum AiAgent { | |
| aider('Aider'), | |
| amp('Amp'), | |
| antigravity('Antigravity'), | |
| augment('Augment'), | |
| claudeCode('Claude Code'), | |
| codex('Codex'), | |
| copilot('Copilot'), | |
| cursor('Cursor'), | |
| devin('Devin'), | |
| gemini('Gemini'), | |
| openCode('OpenCode'), | |
| pi('Pi'), | |
| replit('Replit'), | |
| genericAiAgent('Generic AI Agent'); | |
| final String label; | |
| const AiAgent(this.label); | |
| /// Returns the name of the AI agent executing the tool, if any, | |
| /// by parsing the environment variables. | |
| /// | |
| /// Returns `null` if no AI agent is detected. | |
| static String? detectAgentName(Map<String, String> environment) { | |
| const genericAiAgentLabel = 'Generic AI Agent'; | |
| if (environment.containsKey('CLAUDECODE') || | |
| environment.containsKey('CLAUDE_CODE') || | |
| environment.containsKey('CLAUDE_CODE_IS_COWORK')) { | |
| return claudeCode.label; | |
| } | |
| if (environment.containsKey('ANTIGRAVITY_AGENT')) { | |
| return antigravity.label; | |
| } | |
| if (environment.containsKey('GEMINI_AGENT') || | |
| environment.containsKey('GEMINI_CLI')) { | |
| return gemini.label; | |
| } | |
| if (environment['TERM_PROGRAM'] == 'cursor' || | |
| environment.keys.any((String key) => key.startsWith('CURSOR_'))) { | |
| return cursor.label; | |
| } | |
| if (environment.keys.any( | |
| (String key) => | |
| key.startsWith('COPILOT_') || key.startsWith('GITHUB_COPILOT'), | |
| )) { | |
| return copilot.label; | |
| } | |
| if (environment.containsKey('AIDER') || | |
| environment.keys.any((String key) => key.startsWith('AIDER_'))) { | |
| return aider.label; | |
| } | |
| if (environment.containsKey('DEVIN') || | |
| environment.containsKey('DEVIN_WORKSPACE_ID')) { | |
| return devin.label; | |
| } | |
| if (environment.containsKey('AMP_CURRENT_THREAD_ID')) { | |
| return amp.label; | |
| } | |
| if (environment.containsKey('AUGMENT_AGENT')) { | |
| return augment.label; | |
| } | |
| if (environment.containsKey('CODEX_CI') || | |
| environment.containsKey('CODEX_SANDBOX') || | |
| environment.containsKey('CODEX_THREAD_ID')) { | |
| return codex.label; | |
| } | |
| if (environment.containsKey('OPENCODE') || | |
| environment.containsKey('OPENCODE_CLIENT')) { | |
| return openCode.label; | |
| } | |
| if (environment.containsKey('PI_CODING_AGENT')) { | |
| return pi.label; | |
| } | |
| if (environment.containsKey('REPL_ID')) { | |
| return replit.label; | |
| } | |
| var agent = environment['AGENT']; | |
| if (agent != null && agent.isNotEmpty) { | |
| return agent == '1' ? genericAiAgentLabel : agent; | |
| } | |
| agent = environment['AI_AGENT']; | |
| if (agent != null && agent.isNotEmpty) { | |
| return agent == '1' ? genericAiAgentLabel : agent; | |
| } | |
| if (environment.containsKey('SWE_AGENT')) { | |
| return genericAiAgentLabel; | |
| } | |
| return null; | |
| } | |
| } |