From 810a2f041092fed7914865c61607024957bbeacb Mon Sep 17 00:00:00 2001 From: John Ryan Date: Mon, 10 Aug 2026 16:32:11 -0700 Subject: [PATCH 01/10] Hide the extension settings action when DevTools is running in an IDE. Fixes https://github.com/flutter/devtools/issues/8507 --- .../lib/src/framework/scaffold/scaffold.dart | 8 +++- .../framework/scaffold/scaffold_test.dart | 44 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart index 1f2073e384a..f178b0f90db 100644 --- a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart +++ b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart @@ -57,10 +57,16 @@ class DevToolsScaffold extends StatefulWidget { embedMode: embedMode, ); + /// Returns the list of ScaffoldAction widgets. + /// + /// The button to display the extensions dialog ([ExtensionSettingsAction]) is + /// omitted if DevTools extensions are disabled, hidden via query parameters, + /// or if the DevTools is running in an IDE (EmbedMode.embedOne). static List defaultActions({Color? color}) => [ OpenSettingsAction(color: color), if (FeatureFlags.devToolsExtensions.isEnabled && - !DevToolsQueryParams.load().hideExtensions) + !DevToolsQueryParams.load().hideExtensions && + ideTheme.embedMode != EmbedMode.embedOne) ExtensionSettingsAction(color: color), ReportFeedbackButton(color: color), OpenAboutAction(color: color), diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_test.dart index 74d806eca1f..7ca53f3bf9e 100644 --- a/packages/devtools_app/test/framework/scaffold/scaffold_test.dart +++ b/packages/devtools_app/test/framework/scaffold/scaffold_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. import 'package:devtools_app/devtools_app.dart'; +import 'package:devtools_app/src/extensions/extension_settings.dart'; import 'package:devtools_app/src/framework/scaffold/scaffold.dart'; import 'package:devtools_app/src/shared/framework/framework_controller.dart'; import 'package:devtools_app/src/shared/managers/survey.dart'; @@ -288,6 +289,49 @@ void main() { ); expect(scaffold.actions, isEmpty); }); + + test('defaultActions includes ExtensionSettingsAction based on EmbedMode', () { + setGlobal(IdeTheme, IdeTheme()); + expect( + DevToolsScaffold.defaultActions().any( + (w) => w is ExtensionSettingsAction, + ), + isTrue, + ); + + setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedMany)); + expect( + DevToolsScaffold.defaultActions().any( + (w) => w is ExtensionSettingsAction, + ), + isTrue, + ); + + setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedOne)); + expect( + DevToolsScaffold.defaultActions().any( + (w) => w is ExtensionSettingsAction, + ), + isFalse, + ); + }); + + testWidgets( + 'hides ExtensionSettingsAction in StatusLine for EmbedMode.embedOne', + (WidgetTester tester) async { + setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedOne)); + await tester.pumpWidget( + wrapScaffold( + DevToolsScaffold( + screens: const [_screen1], + page: _screen1.screenId, + embedMode: EmbedMode.embedOne, + ), + ), + ); + expect(find.byType(ExtensionSettingsAction), findsNothing); + }, + ); } class _TestScreen extends Screen { From 7e235a26ce7a320f2033de202db9a35b2c2ae42a Mon Sep 17 00:00:00 2001 From: John Ryan Date: Mon, 10 Aug 2026 16:43:23 -0700 Subject: [PATCH 02/10] Ensure that the extensions action is displayed when showing an extension on screen, even when embedded in an IDE. --- .../lib/src/framework/scaffold/scaffold.dart | 36 ++++++++++++------- .../src/framework/scaffold/status_line.dart | 5 ++- .../framework/scaffold/scaffold_test.dart | 18 ++++++++-- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart index f178b0f90db..8957b0890bd 100644 --- a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart +++ b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../app.dart'; +import '../../extensions/extension_screen.dart'; import '../../extensions/extension_settings.dart'; import '../../screens/debugger/debugger_screen.dart'; import '../../shared/analytics/prompt.dart'; @@ -58,19 +59,28 @@ class DevToolsScaffold extends StatefulWidget { ); /// Returns the list of ScaffoldAction widgets. - /// - /// The button to display the extensions dialog ([ExtensionSettingsAction]) is - /// omitted if DevTools extensions are disabled, hidden via query parameters, - /// or if the DevTools is running in an IDE (EmbedMode.embedOne). - static List defaultActions({Color? color}) => [ - OpenSettingsAction(color: color), - if (FeatureFlags.devToolsExtensions.isEnabled && - !DevToolsQueryParams.load().hideExtensions && - ideTheme.embedMode != EmbedMode.embedOne) - ExtensionSettingsAction(color: color), - ReportFeedbackButton(color: color), - OpenAboutAction(color: color), - ]; + static List defaultActions({ + Color? color, + Screen? currentScreen, + }) { + final queryParams = DevToolsQueryParams.load(); + + // If DevTools is running in an IDE (EmbedMode.embedOne), then hide + // [ExtensionSettingsAction], unless this screen is showing an extension. + final showExtensionSettings = + FeatureFlags.devToolsExtensions.isEnabled && + !queryParams.hideExtensions && + (ideTheme.embedMode != EmbedMode.embedOne || + currentScreen is ExtensionScreen || + queryParams.hideAllExceptExtensions); + + return [ + OpenSettingsAction(color: color), + if (showExtensionSettings) ExtensionSettingsAction(color: color), + ReportFeedbackButton(color: color), + OpenAboutAction(color: color), + ]; + } /// The padding around the content in the DevTools UI. EdgeInsets get appPadding => EdgeInsets.fromLTRB( diff --git a/packages/devtools_app/lib/src/framework/scaffold/status_line.dart b/packages/devtools_app/lib/src/framework/scaffold/status_line.dart index 54e78dc2954..c638f7fde8b 100644 --- a/packages/devtools_app/lib/src/framework/scaffold/status_line.dart +++ b/packages/devtools_app/lib/src/framework/scaffold/status_line.dart @@ -124,7 +124,10 @@ class StatusLine extends StatelessWidget { BulletSpacer(color: foregroundColor), Row( crossAxisAlignment: CrossAxisAlignment.end, - children: DevToolsScaffold.defaultActions(color: foregroundColor), + children: DevToolsScaffold.defaultActions( + color: foregroundColor, + currentScreen: currentScreen, + ), ), ], ]; diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_test.dart index 7ca53f3bf9e..19f8d6fe990 100644 --- a/packages/devtools_app/test/framework/scaffold/scaffold_test.dart +++ b/packages/devtools_app/test/framework/scaffold/scaffold_test.dart @@ -3,8 +3,10 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. import 'package:devtools_app/devtools_app.dart'; +import 'package:devtools_app/src/extensions/extension_screen.dart'; import 'package:devtools_app/src/extensions/extension_settings.dart'; import 'package:devtools_app/src/framework/scaffold/scaffold.dart'; +import 'package:devtools_app/src/shared/development_helpers.dart'; import 'package:devtools_app/src/shared/framework/framework_controller.dart'; import 'package:devtools_app/src/shared/managers/survey.dart'; import 'package:devtools_app/src/shared/primitives/query_parameters.dart'; @@ -290,7 +292,7 @@ void main() { expect(scaffold.actions, isEmpty); }); - test('defaultActions includes ExtensionSettingsAction based on EmbedMode', () { + test('defaultActions includes ExtensionSettingsAction based on EmbedMode and screen type', () { setGlobal(IdeTheme, IdeTheme()); expect( DevToolsScaffold.defaultActions().any( @@ -308,12 +310,24 @@ void main() { ); setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedOne)); + // Standard screen in embedOne mode hides ExtensionSettingsAction expect( - DevToolsScaffold.defaultActions().any( + DevToolsScaffold.defaultActions(currentScreen: _screen1).any( (w) => w is ExtensionSettingsAction, ), isFalse, ); + + // ExtensionScreen in embedOne mode shows ExtensionSettingsAction + final extensionScreen = ExtensionScreen( + StubDevToolsExtensions.fooExtension, + ); + expect( + DevToolsScaffold.defaultActions(currentScreen: extensionScreen).any( + (w) => w is ExtensionSettingsAction, + ), + isTrue, + ); }); testWidgets( From 2fc3298ea3807c32589c6e0eac28607ca59a8265 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Mon, 10 Aug 2026 17:00:08 -0700 Subject: [PATCH 03/10] Replace https://flutter.dev/ with a data placeholder in _controller_web.dart to prevent browser X-Frame-Options iframe errors during local debugging. --- .../extensions/embedded/_controller_web.dart | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart b/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart index 1da1d1846ae..905457143a5 100644 --- a/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart +++ b/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart @@ -42,7 +42,30 @@ class EmbeddedExtensionControllerImpl extends EmbeddedExtensionController String get extensionUrl { if (debugDevToolsExtensions && !isDevToolsServerAvailable) { - return 'https://flutter.dev/'; + return 'data:text/html;charset=utf-8,${Uri.encodeComponent(''' + + + + + + +

DevTools Extension Placeholder (${extensionConfig.name})

+

Local debugging placeholder view.

+ + +''')}'; } final basePath = devtoolsAssetsBasePath( From 0f4a7f96beedc7ab242168f486b0a5ffca3baa9a Mon Sep 17 00:00:00 2001 From: John Ryan Date: Mon, 10 Aug 2026 17:05:24 -0700 Subject: [PATCH 04/10] Add debugging devtools extensions skill --- .../debugging-devtools-extensions/SKILL.md | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .agents/skills/debugging-devtools-extensions/SKILL.md diff --git a/.agents/skills/debugging-devtools-extensions/SKILL.md b/.agents/skills/debugging-devtools-extensions/SKILL.md new file mode 100644 index 00000000000..9fbebfa20e5 --- /dev/null +++ b/.agents/skills/debugging-devtools-extensions/SKILL.md @@ -0,0 +1,79 @@ +--- +name: debugging-devtools-extensions +description: Guidelines and step-by-step workflow for debugging DevTools extensions locally, including stub mode, fixed-port launching, browser auto-opening, URL query parameters, target app connection, and human-in-the-loop interaction. Use when debugging or testing DevTools extension behavior. +--- + +# Debugging DevTools Extensions + +Follow this workflow to test and debug DevTools extensions locally. + +## 1. Local Stub Extensions Mode (No Server Needed) + +When running DevTools in standalone web mode (`flutter run -d chrome`), DevTools does not run the `devtools_server` backend by default. To test extensions without a running server backend: + +1. Open [`packages/devtools_app/lib/src/shared/development_helpers.dart`](file:///Users/ryjohn/code/github/flutter/devtools/packages/devtools_app/lib/src/shared/development_helpers.dart#L57). +2. Set `const _debugDevToolsExtensions = true;`. + +> [!WARNING] +> Never commit `_debugDevToolsExtensions = true;` to git. A repository unit test (`development_helpers_test.dart`) enforces that this flag remains `false`. + +Activating stub mode registers the following mock extensions: +- `foo_ext` (`package:foo`) +- `bar_ext` (`package:bar`) +- `provider_ext` (`package:provider`) + +## 2. Automated Launch & Browser Navigation + +The agent can automate running DevTools AND launching the browser directly to the target URL: + +### Step 2a: Launch DevTools on a Fixed Port +In `packages/devtools_app`, launch DevTools specifying a fixed `--web-port`: +```bash +flutter run -d chrome --web-port=52941 +``` + +### Step 2b: Open Browser to Target URL Automatically +Use the system OS open command to launch Chrome/browser directly to the desired test URL: + +- **macOS**: `open "http://localhost:52941/foo_ext?embedMode=one"` +- **Linux**: `xdg-open "http://localhost:52941/foo_ext?embedMode=one"` +- **Windows**: `start "http://localhost:52941/foo_ext?embedMode=one"` + +## 3. Testing Extension URLs & Embed Modes + +Navigating to specific query parameters tests different extension UI states: + +- **Single Extension Screen (`embedOne`)**: + `http://localhost:52941/foo_ext?embedMode=one` + *(Renders single extension view; puzzle piece icon IS visible in status bar)* + +- **Extensions-Only View**: + `http://localhost:52941/?hide=all-except-extensions&embedMode=many` + *(Renders only extension tabs; puzzle piece icon IS visible)* + +- **Standard Core Screen (`embedOne`)**: + `http://localhost:52941/inspector?embedMode=one` + *(Renders standard tool panel; puzzle piece icon IS HIDDEN)* + +## 4. Connecting to an End-User Target App + +To test against real pub package extensions: + +1. Run the sample app in `packages/devtools_extensions/example/app_that_uses_foo`: + ```bash + cd packages/devtools_extensions/example/app_that_uses_foo + flutter run -d chrome + ``` +2. Ask the user to copy/paste the VM Service URI from the terminal output (e.g. `ws://127.0.0.1:8181/xxx=/ws`). +3. Open the browser automatically with the `uri` parameter: + ```bash + open "http://localhost:52941/foo_ext?embedMode=one&uri=" + ``` + +## 5. Human Interaction & User Prompting Steps + +When an AI agent is performing this workflow: + +- **Obtaining VM Service URI**: When connecting to a target app, ask the user to provide the VM Service URI printed in the target app's console output (using `ask_question` or a direct prompt). +- **Automated Browser Opening**: The agent should launch DevTools and execute `open ` to launch the browser automatically. +- **Manual Visual Verification**: Ask the user to inspect the opened browser window and confirm whether the expected extension UI or status bar button appears. From 61fb530e8cf895159680600120e7045192bfba14 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Mon, 10 Aug 2026 17:08:19 -0700 Subject: [PATCH 05/10] add to release notes --- packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index 2d797c8109e..f734451ed1a 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md @@ -69,7 +69,8 @@ TODO: Remove this section if there are not any updates. ## DevTools extension updates -TODO: Remove this section if there are not any updates. +* Hide the DevTools extensions menu button in single-screen embedded mode (`EmbedMode.embedOne`) on standard screens. + [#8507](https://github.com/flutter/devtools/issues/8507) ## Advanced developer mode updates From cbdb186a08a2da4f2272833314b6b655d752bdb8 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Tue, 11 Aug 2026 09:20:37 -0700 Subject: [PATCH 06/10] format --- .../lib/src/framework/scaffold/scaffold.dart | 5 +- .../framework/scaffold/scaffold_test.dart | 71 ++++++++++--------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart index 8957b0890bd..13e92675130 100644 --- a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart +++ b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart @@ -59,10 +59,7 @@ class DevToolsScaffold extends StatefulWidget { ); /// Returns the list of ScaffoldAction widgets. - static List defaultActions({ - Color? color, - Screen? currentScreen, - }) { + static List defaultActions({Color? color, Screen? currentScreen}) { final queryParams = DevToolsQueryParams.load(); // If DevTools is running in an IDE (EmbedMode.embedOne), then hide diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_test.dart index 19f8d6fe990..50749322124 100644 --- a/packages/devtools_app/test/framework/scaffold/scaffold_test.dart +++ b/packages/devtools_app/test/framework/scaffold/scaffold_test.dart @@ -292,43 +292,46 @@ void main() { expect(scaffold.actions, isEmpty); }); - test('defaultActions includes ExtensionSettingsAction based on EmbedMode and screen type', () { - setGlobal(IdeTheme, IdeTheme()); - expect( - DevToolsScaffold.defaultActions().any( - (w) => w is ExtensionSettingsAction, - ), - isTrue, - ); + test( + 'defaultActions includes ExtensionSettingsAction based on EmbedMode and screen type', + () { + setGlobal(IdeTheme, IdeTheme()); + expect( + DevToolsScaffold.defaultActions().any( + (w) => w is ExtensionSettingsAction, + ), + isTrue, + ); - setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedMany)); - expect( - DevToolsScaffold.defaultActions().any( - (w) => w is ExtensionSettingsAction, - ), - isTrue, - ); + setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedMany)); + expect( + DevToolsScaffold.defaultActions().any( + (w) => w is ExtensionSettingsAction, + ), + isTrue, + ); - setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedOne)); - // Standard screen in embedOne mode hides ExtensionSettingsAction - expect( - DevToolsScaffold.defaultActions(currentScreen: _screen1).any( - (w) => w is ExtensionSettingsAction, - ), - isFalse, - ); + setGlobal(IdeTheme, IdeTheme(embedMode: EmbedMode.embedOne)); + // Standard screen in embedOne mode hides ExtensionSettingsAction + expect( + DevToolsScaffold.defaultActions( + currentScreen: _screen1, + ).any((w) => w is ExtensionSettingsAction), + isFalse, + ); - // ExtensionScreen in embedOne mode shows ExtensionSettingsAction - final extensionScreen = ExtensionScreen( - StubDevToolsExtensions.fooExtension, - ); - expect( - DevToolsScaffold.defaultActions(currentScreen: extensionScreen).any( - (w) => w is ExtensionSettingsAction, - ), - isTrue, - ); - }); + // ExtensionScreen in embedOne mode shows ExtensionSettingsAction + final extensionScreen = ExtensionScreen( + StubDevToolsExtensions.fooExtension, + ); + expect( + DevToolsScaffold.defaultActions( + currentScreen: extensionScreen, + ).any((w) => w is ExtensionSettingsAction), + isTrue, + ); + }, + ); testWidgets( 'hides ExtensionSettingsAction in StatusLine for EmbedMode.embedOne', From 23674f16407800d427e9fd5926b7d7e937294c0c Mon Sep 17 00:00:00 2001 From: John Ryan Date: Wed, 12 Aug 2026 14:41:41 -0700 Subject: [PATCH 07/10] Apply suggestions from code review Co-authored-by: Kenzie Davisson <43759233+kenzieschmoll@users.noreply.github.com> --- .agents/skills/debugging-devtools-extensions/SKILL.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.agents/skills/debugging-devtools-extensions/SKILL.md b/.agents/skills/debugging-devtools-extensions/SKILL.md index 9fbebfa20e5..60858d08a2d 100644 --- a/.agents/skills/debugging-devtools-extensions/SKILL.md +++ b/.agents/skills/debugging-devtools-extensions/SKILL.md @@ -45,15 +45,15 @@ Navigating to specific query parameters tests different extension UI states: - **Single Extension Screen (`embedOne`)**: `http://localhost:52941/foo_ext?embedMode=one` - *(Renders single extension view; puzzle piece icon IS visible in status bar)* + *(Renders single extension view like extensions are rendered inside VS Code. In this mode, the extensions settings button, a puzzle piece icon, IS visible in the bottom status bar)* -- **Extensions-Only View**: +- **Extensions-Only View (`embedMany`)**: `http://localhost:52941/?hide=all-except-extensions&embedMode=many` - *(Renders only extension tabs; puzzle piece icon IS visible)* + *(Renders only extension tabs like extensions are rendered inside IntelliJ/Android Studio. In this mode, the extensions settings button, a puzzle piece icon, IS visible in the top tab bar)* - **Standard Core Screen (`embedOne`)**: `http://localhost:52941/inspector?embedMode=one` - *(Renders standard tool panel; puzzle piece icon IS HIDDEN)* + *(Renders standard tool panel like they are rendered in VS Code. In this mode, the extensions settings button, a puzzle piece icon, IS HIDDEN)* ## 4. Connecting to an End-User Target App From 5d06a2d98fd6658c77343e978d8b1e237873ca7b Mon Sep 17 00:00:00 2001 From: John Ryan Date: Wed, 12 Aug 2026 14:51:52 -0700 Subject: [PATCH 08/10] Use OS-based browser opening commands --- .../skills/debugging-devtools-extensions/SKILL.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.agents/skills/debugging-devtools-extensions/SKILL.md b/.agents/skills/debugging-devtools-extensions/SKILL.md index 60858d08a2d..2958f7aed09 100644 --- a/.agents/skills/debugging-devtools-extensions/SKILL.md +++ b/.agents/skills/debugging-devtools-extensions/SKILL.md @@ -65,15 +65,15 @@ To test against real pub package extensions: flutter run -d chrome ``` 2. Ask the user to copy/paste the VM Service URI from the terminal output (e.g. `ws://127.0.0.1:8181/xxx=/ws`). -3. Open the browser automatically with the `uri` parameter: - ```bash - open "http://localhost:52941/foo_ext?embedMode=one&uri=" - ``` +3. Open the browser automatically with the `uri` parameter using the appropriate OS command (as described in Step 2b): + - **macOS**: `open "http://localhost:52941/foo_ext?embedMode=one&uri="` + - **Linux**: `xdg-open "http://localhost:52941/foo_ext?embedMode=one&uri="` + - **Windows**: `start "http://localhost:52941/foo_ext?embedMode=one&uri="` ## 5. Human Interaction & User Prompting Steps When an AI agent is performing this workflow: - **Obtaining VM Service URI**: When connecting to a target app, ask the user to provide the VM Service URI printed in the target app's console output (using `ask_question` or a direct prompt). -- **Automated Browser Opening**: The agent should launch DevTools and execute `open ` to launch the browser automatically. -- **Manual Visual Verification**: Ask the user to inspect the opened browser window and confirm whether the expected extension UI or status bar button appears. +- **Automated Browser Opening**: The agent should launch DevTools and execute the appropriate OS command (`open`, `xdg-open`, or `start` as described in Step 2b) to launch the browser automatically. +- **Manual Visual Verification**: Ask the user to inspect the opened browser window and confirm whether the expected extension UI or behavior is visible. From 5dd83be753cf753fa33033e0fca4a0d9a5b60698 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Wed, 12 Aug 2026 14:56:05 -0700 Subject: [PATCH 09/10] Refactor HTML into a function --- .../extensions/embedded/_controller_web.dart | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart b/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart index 905457143a5..ab96f867ec0 100644 --- a/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart +++ b/packages/devtools_app/lib/src/extensions/embedded/_controller_web.dart @@ -30,19 +30,10 @@ import 'controller.dart'; /// [ui_web.PlatformViewRegistry], which [_viewIdIncrementer] is used to create. var _viewIdIncrementer = 0; -class EmbeddedExtensionControllerImpl extends EmbeddedExtensionController - with AutoDisposeControllerMixin { - EmbeddedExtensionControllerImpl(super.extensionConfig); - - /// The view id for the extension iFrame. - /// - /// See [_viewIdIncrementer] for an explanation of why we use an incrementer - /// in the id. - late final viewId = 'ext-${extensionConfig.name}-${_viewIdIncrementer++}'; - - String get extensionUrl { - if (debugDevToolsExtensions && !isDevToolsServerAvailable) { - return 'data:text/html;charset=utf-8,${Uri.encodeComponent(''' +/// HTML template for the placeholder view used when debugging extensions without +/// a running DevTools server. +String _debugExtensionPlaceholderHtml(String name) { + return ''' @@ -61,11 +52,27 @@ class EmbeddedExtensionControllerImpl extends EmbeddedExtensionController -

DevTools Extension Placeholder (${extensionConfig.name})

+

DevTools Extension Placeholder ($name)

Local debugging placeholder view.

-''')}'; +'''; +} + +class EmbeddedExtensionControllerImpl extends EmbeddedExtensionController + with AutoDisposeControllerMixin { + EmbeddedExtensionControllerImpl(super.extensionConfig); + + /// The view id for the extension iFrame. + /// + /// See [_viewIdIncrementer] for an explanation of why we use an incrementer + /// in the id. + late final viewId = 'ext-${extensionConfig.name}-${_viewIdIncrementer++}'; + + String get extensionUrl { + if (debugDevToolsExtensions && !isDevToolsServerAvailable) { + final html = _debugExtensionPlaceholderHtml(extensionConfig.name); + return 'data:text/html;charset=utf-8,${Uri.encodeComponent(html)}'; } final basePath = devtoolsAssetsBasePath( From 24155f986329417681fcf26a34bfb3e746e28e06 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Wed, 12 Aug 2026 15:02:56 -0700 Subject: [PATCH 10/10] remove embedMode information from skill, since it's unrelated --- .../debugging-devtools-extensions/SKILL.md | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/.agents/skills/debugging-devtools-extensions/SKILL.md b/.agents/skills/debugging-devtools-extensions/SKILL.md index 2958f7aed09..5fbb2e4e881 100644 --- a/.agents/skills/debugging-devtools-extensions/SKILL.md +++ b/.agents/skills/debugging-devtools-extensions/SKILL.md @@ -39,23 +39,7 @@ Use the system OS open command to launch Chrome/browser directly to the desired - **Linux**: `xdg-open "http://localhost:52941/foo_ext?embedMode=one"` - **Windows**: `start "http://localhost:52941/foo_ext?embedMode=one"` -## 3. Testing Extension URLs & Embed Modes - -Navigating to specific query parameters tests different extension UI states: - -- **Single Extension Screen (`embedOne`)**: - `http://localhost:52941/foo_ext?embedMode=one` - *(Renders single extension view like extensions are rendered inside VS Code. In this mode, the extensions settings button, a puzzle piece icon, IS visible in the bottom status bar)* - -- **Extensions-Only View (`embedMany`)**: - `http://localhost:52941/?hide=all-except-extensions&embedMode=many` - *(Renders only extension tabs like extensions are rendered inside IntelliJ/Android Studio. In this mode, the extensions settings button, a puzzle piece icon, IS visible in the top tab bar)* - -- **Standard Core Screen (`embedOne`)**: - `http://localhost:52941/inspector?embedMode=one` - *(Renders standard tool panel like they are rendered in VS Code. In this mode, the extensions settings button, a puzzle piece icon, IS HIDDEN)* - -## 4. Connecting to an End-User Target App +## 3. Connecting to an End-User Target App To test against real pub package extensions: @@ -70,7 +54,7 @@ To test against real pub package extensions: - **Linux**: `xdg-open "http://localhost:52941/foo_ext?embedMode=one&uri="` - **Windows**: `start "http://localhost:52941/foo_ext?embedMode=one&uri="` -## 5. Human Interaction & User Prompting Steps +## 4. Human Interaction & User Prompting Steps When an AI agent is performing this workflow: