- Added
DashToolKindandDashTool.kindto distinguish top-level tools from
shared components, plusDashTool.canBeRootTool. - Added shared-component
DashToolvalues:analysisServer
(analysis-server),dartMcpServer(dart-mcp-server), andskillsCli
(skills-cli). topLevelTool()now ignores aDASH__TOOLvalue that names a shared
component and falls back to the current tool.- Deprecated
topLevelTool(). Tools no longer need to readDASH__TOOL
themselves: pass your own tool toAnalytics, which resolves the root tool,
and usegetEnvironment()for child processes. Analyticsnow resolves the root tool (the user's entry point) from
DASH__TOOL, then an optional newfallbackRootToolparameter on
AnalyticsandAnalytics.development, then the tool itself. Only tools,
never shared components, can be the root tool.- Every event now carries two new user properties:
root_tool, the resolved
root tool, andleaf_tool, the logical tool passed astooltoAnalytics
(a top-level tool or a shared component). - The
tooluser property keeps its current value, the tool itself for a
top-level tool and the root tool for a shared component, so existing
dashboards keep working. It's deprecated and will be removed in a future
release. LogFileStats.toolCountnow counts events by leaf tool, falling back to
toolfor log records written beforeleaf_toolexisted.- Added
fallbackRootToolandrootTool(a test-only override) parameters to
Analytics.fake, which resolvesDASH__TOOLfrom itsenvironment. - Opt-in status, the first-run and consent-message-version checks,
clientShowedMessage(), andgetConsentMessageare now keyed on the root
tool instead of the tool. A shared component never shows its own consent
message or gets its own line in the config file. - If no root tool resolves, which can only happen for a shared component,
analytics are disabled for the session, in internal builds too: the
Analyticsfactories return aNoOpAnalytics, and other instances report
okToSend == false, show no consent message, and never write to the config
file. - Fixed
getEnvironment()to setDASH__TOOLto the tool's label (for
examplevscode-plugins) instead of its Dart enum name (vscodePlugins),
whichDashTool.fromLabelrejected. It now passes on the resolved root
tool, so a shared component never passes on itself, and leaves out
DASH__TOOLwhen no root tool resolves.