Skip to content

Commit 6fb811a

Browse files
committed
Adding some claude skills for working with intellij plugins
1 parent 72fed00 commit 6fb811a

30 files changed

Lines changed: 4330 additions & 0 deletions

File tree

.claude/skills/intellij-plugin-dev-workspace/iteration-1/benchmark.json

Lines changed: 323 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Skill Benchmark: intellij-plugin-dev
2+
3+
**Model**: <model-name>
4+
**Date**: 2026-03-16T04:00:26Z
5+
**Evals**: 1, 2, 3 (3 runs each per configuration)
6+
7+
## Summary
8+
9+
| Metric | With Skill | Without Skill | Delta |
10+
|--------|------------|---------------|-------|
11+
| Pass Rate | 89% ± 19% | 61% ± 54% | +0.28 |
12+
| Time | 209.9s ± 69.1s | 78.2s ± 14.8s | +131.7s |
13+
| Tokens | 73574 ± 22663 | 27185 ± 709 | +46390 |
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"eval_id": 1,
3+
"eval_name": "windows-debug-errors",
4+
"prompt": "In the flutter-intellij plugin, I'm seeing that when I run a Flutter Windows desktop app in debug mode, exceptions thrown by the Flutter framework are not appearing in the IntelliJ console. The same app works fine on Chrome. What's the code path responsible for showing these errors, and where is the most likely failure point on Windows? Walk me through the relevant classes and show where you'd add a fix.",
5+
"assertions": [
6+
{
7+
"id": "mentions-structured-errors",
8+
"text": "Mentions ext.flutter.inspector.structuredErrors or structured errors being enabled as the reason Chrome differs from Windows"
9+
},
10+
{
11+
"id": "mentions-flutter-console-log-manager",
12+
"text": "Mentions FlutterConsoleLogManager or handleFlutterErrorEvent as the handler for Flutter.Error events"
13+
},
14+
{
15+
"id": "identifies-silent-catch",
16+
"text": "Identifies the silent exception catch (try/catch that only logs a warning) in processFlutterErrorEvent as the failure point"
17+
},
18+
{
19+
"id": "proposes-concrete-fix",
20+
"text": "Proposes a concrete fix — either a fallback to display raw error text on exception, or adds error visibility when processFlutterErrorEvent throws"
21+
},
22+
{
23+
"id": "explains-chrome-difference",
24+
"text": "Explains why Chrome works differently (extension not available on web, so app.log path is used instead)"
25+
}
26+
]
27+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Flutter Windows Desktop: Missing Debug Console Errors
2+
3+
## The error display code path (structured errors enabled)
4+
5+
When `isShowStructuredErrors()` is true, the plugin enables `ext.flutter.inspector.structuredErrors`
6+
via `FlutterApp.getFlutterConsoleLogManager()`. Once enabled, Flutter **suppresses** `app.log`
7+
error events and instead sends `Flutter.Error` VM service extension events on the `Extension` stream.
8+
9+
The full chain:
10+
11+
```
12+
Flutter framework error → FlutterError.presentError()
13+
14+
Flutter.Error VM service extension event (Extension stream)
15+
16+
VMServiceManager.onVmServiceReceived("Flutter.Error") [VMServiceManager.java:207]
17+
18+
app.getFlutterConsoleLogManager().handleFlutterErrorEvent(event)
19+
20+
queue.add(() -> processFlutterErrorEvent(diagnosticsNode)) [FlutterConsoleLogManager.java:133]
21+
22+
processFlutterErrorEvent() → console.print(header/properties/footer)
23+
```
24+
25+
## Why Chrome works but Windows does not
26+
27+
On Chrome/web, `ext.flutter.inspector.structuredErrors` is **not available**, so the callback
28+
in `hasServiceExtension(...)` never fires, structured errors stay disabled, and Flutter errors
29+
come through the normal `app.log` daemon event path which works reliably.
30+
31+
On Windows desktop, the extension IS available, so:
32+
1. Structured errors get enabled
33+
2. `app.log` error events are suppressed by Flutter
34+
3. Errors must flow through `processFlutterErrorEvent()` — and that's where they die silently
35+
36+
## The specific failure point
37+
38+
**`DiagnosticsNode.getStyleMember()` at line 504 of `DiagnosticsNode.java`:**
39+
40+
```java
41+
private DiagnosticsTreeStyle getStyleMember(String memberName, DiagnosticsTreeStyle defaultValue) {
42+
if (!json.has(memberName)) {
43+
return defaultValue;
44+
}
45+
final JsonElement value = json.get(memberName);
46+
if (value instanceof JsonNull) {
47+
return defaultValue;
48+
}
49+
return DiagnosticsTreeStyle.valueOf(value.getAsString()); // ← NO try/catch
50+
}
51+
```
52+
53+
Compare with the safe `getLevelMember()` just above it, which has:
54+
55+
```java
56+
catch (IllegalArgumentException ignore) {
57+
return defaultValue;
58+
}
59+
```
60+
61+
If the Windows Flutter SDK emits a `style` value not present in the plugin's `DiagnosticsTreeStyle`
62+
enum, `valueOf()` throws `IllegalArgumentException`. This propagates out of `processFlutterErrorEvent()`
63+
and is caught by the queue lambda's `catch (Throwable t)` at line 137:
64+
65+
```java
66+
catch (Throwable t) {
67+
if (FlutterSettings.getInstance().isVerboseLogging()) {
68+
LOG.warn(t);
69+
} else {
70+
LOG.warn("Error processing FlutterErrorEvent: " + t.getMessage());
71+
}
72+
}
73+
```
74+
75+
The error goes to `idea.log` only. Nothing appears in the console.
76+
77+
## The fix — two parts
78+
79+
### Part 1: Fix `getStyleMember()` to match `getLevelMember()`
80+
81+
In `src/io/flutter/logging/DiagnosticsNode.java`, line 496–505:
82+
83+
```java
84+
private DiagnosticsTreeStyle getStyleMember(String memberName, DiagnosticsTreeStyle defaultValue) {
85+
if (!json.has(memberName)) {
86+
return defaultValue;
87+
}
88+
final JsonElement value = json.get(memberName);
89+
if (value instanceof JsonNull) {
90+
return defaultValue;
91+
}
92+
try {
93+
return DiagnosticsTreeStyle.valueOf(value.getAsString());
94+
}
95+
catch (IllegalArgumentException ignore) {
96+
return defaultValue;
97+
}
98+
}
99+
```
100+
101+
### Part 2: Add fallback console output in the queue catch block
102+
103+
In `FlutterConsoleLogManager.java`, line 133–151, change the catch to also emit a raw error:
104+
105+
```java
106+
queue.add(() -> {
107+
try {
108+
processFlutterErrorEvent(diagnosticsNode);
109+
}
110+
catch (Throwable t) {
111+
// Fallback: show the raw error text so it's never silently swallowed
112+
final String rawError = diagnosticsNode.getDescription();
113+
if (rawError != null && !rawError.isEmpty()) {
114+
console.print(rawError + "\n", ConsoleViewContentType.ERROR_OUTPUT);
115+
}
116+
LOG.warn("Error processing FlutterErrorEvent: " + t.getMessage());
117+
}
118+
finally { ... }
119+
});
120+
```
121+
122+
## Key files
123+
124+
| File | Location | Role |
125+
|------|----------|------|
126+
| `DiagnosticsNode.java` | `src/io/flutter/logging/` | **Fix site**`getStyleMember()` line 504 |
127+
| `FlutterConsoleLogManager.java` | `src/io/flutter/logging/` | Silent swallow site — line 137 |
128+
| `VMServiceManager.java` | `src/io/flutter/vmService/` | Routes `Flutter.Error` events |
129+
| `FlutterApp.java` | `src/io/flutter/run/daemon/` | Enables `structuredErrors` — lines 633–649 |
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"eval_id": 1,
3+
"run_type": "with_skill",
4+
"expectations": [
5+
{
6+
"text": "Mentions ext.flutter.inspector.structuredErrors or structured errors being enabled as the reason Chrome differs from Windows",
7+
"passed": true,
8+
"evidence": "The response explicitly states 'When isShowStructuredErrors() is true, the plugin enables ext.flutter.inspector.structuredErrors via FlutterApp.getFlutterConsoleLogManager()' and explains that 'On Chrome/web, ext.flutter.inspector.structuredErrors is not available, so the callback in hasServiceExtension(...) never fires, structured errors stay disabled'"
9+
},
10+
{
11+
"text": "Mentions FlutterConsoleLogManager or handleFlutterErrorEvent as the handler for Flutter.Error events",
12+
"passed": true,
13+
"evidence": "The response shows the full chain including 'app.getFlutterConsoleLogManager().handleFlutterErrorEvent(event)' and 'queue.add(() -> processFlutterErrorEvent(diagnosticsNode)) [FlutterConsoleLogManager.java:133]'"
14+
},
15+
{
16+
"text": "Identifies the silent exception catch (try/catch that only logs a warning) in processFlutterErrorEvent as the failure point",
17+
"passed": true,
18+
"evidence": "The response shows the catch block at line 137: 'catch (Throwable t) { if (FlutterSettings.getInstance().isVerboseLogging()) { LOG.warn(t); } else { LOG.warn(\"Error processing FlutterErrorEvent: \" + t.getMessage()); } }' and notes 'The error goes to idea.log only. Nothing appears in the console.'"
19+
},
20+
{
21+
"text": "Proposes a concrete fix \u00e2\u20ac\u201d either a fallback to display raw error text on exception, or adds error visibility when processFlutterErrorEvent throws",
22+
"passed": true,
23+
"evidence": "The response proposes two concrete fixes: Part 1 fixes getStyleMember() to add a try/catch matching getLevelMember(), and Part 2 adds a fallback console.print(rawError, ERROR_OUTPUT) in the catch block so errors are never silently swallowed."
24+
},
25+
{
26+
"text": "Explains why Chrome works differently (extension not available on web, so app.log path is used instead)",
27+
"passed": true,
28+
"evidence": "The response states 'On Chrome/web, ext.flutter.inspector.structuredErrors is not available, so the callback in hasServiceExtension(...) never fires, structured errors stay disabled, and Flutter errors come through the normal app.log daemon event path which works reliably.'"
29+
}
30+
],
31+
"summary": {
32+
"passed": 5,
33+
"failed": 0,
34+
"total": 5,
35+
"pass_rate": 1.0
36+
}
37+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"total_tokens": 99378,
3+
"duration_ms": 230008,
4+
"total_duration_seconds": 230.0
5+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Flutter Windows Desktop Debug Exceptions Not Appearing in IntelliJ Console
2+
3+
## Overview
4+
5+
When a Flutter Windows desktop app runs in debug mode via the flutter-intellij plugin, exceptions thrown by the Flutter framework should appear in the IntelliJ "Run" or "Debug" console. The fact that Chrome works but Windows does not points to a platform-specific divergence in how the plugin launches the process, attaches the debugger, or routes stderr/stdout from the running process.
6+
7+
## The Error Display Pipeline
8+
9+
### 1. Process Launch — `FlutterApp` / `FlutterLaunchTask`
10+
11+
The entry point is the run configuration execution chain. When the user hits "Debug", IntelliJ calls the plugin's `RunProfileState`, which delegates to a `FlutterLaunchTask`. This task builds the `flutter run` command line, starts the process via `GeneralCommandLine` / `OSProcessHandler`, and returns a `ProcessHandler` that IntelliJ attaches to the console.
12+
13+
For Chrome the device ID is `chrome`; for Windows desktop it is `windows`. Both call `flutter run`, but output handling diverges.
14+
15+
### 2. Process Handler — `OSProcessHandler` / `FlutterApp`
16+
17+
`OSProcessHandler` reads stdout and stderr from the child process and broadcasts `ProcessEvent`s to registered `ProcessListener`s. IntelliJ's console view is one such listener. Key plugin classes involved:
18+
19+
- **`FlutterApp`** — wraps the running `flutter run` process and acts as central coordinator.
20+
- **`DaemonApi` / `FlutterDaemonService`** — communicates with the Flutter tool daemon (JSON-RPC over stdin/stdout). The daemon sends structured events including `app.log`, `app.progress`, and error events.
21+
- **`FlutterConsoleFilter`** — post-processes console lines (e.g., makes Dart file URIs clickable) but does not suppress them.
22+
23+
### 3. Daemon vs. Direct Output — the Critical Branch
24+
25+
- **Chrome**: Flutter's web tooling often emits errors directly to **stderr** of the `flutter run` process, which flows straight through `OSProcessHandler` to the console.
26+
- **Windows desktop**: Framework-level exceptions (the `FlutterError.onError` red-box output) travel through a **`app.log` daemon event** — a structured JSON message that the plugin must explicitly listen for and forward to the console.
27+
28+
If the `app.log` listener is not registered, the errors are silently dropped even though the Flutter tool is emitting them correctly.
29+
30+
## Most Likely Failure Points on Windows
31+
32+
### Failure Point A: `app.log` listener not wired up for desktop targets
33+
34+
The listener registration code may have a device-type guard that inadvertently excludes desktop:
35+
36+
```java
37+
if (device.isWeb()) {
38+
// handle raw stderr
39+
} else if (device.isMobile()) {
40+
// register app.log listener
41+
}
42+
// desktop falls through — no listener registered!
43+
```
44+
45+
This is the highest-probability cause. The fix is ensuring the `app.log` registration runs for all device types, including desktop.
46+
47+
### Failure Point B: `ConsoleView` reference is null for the desktop debug session
48+
49+
After the debug session starts, the plugin attaches an `XDebugSession`. The `ConsoleView` used during the pre-debug launch phase may differ from the one shown in the Debug tool window. If the plugin resolves the console by looking up the `RunContentDescriptor` and that lookup fails for the desktop configuration, `console` is null. The handler then silently no-ops:
50+
51+
```java
52+
if (console != null) {
53+
console.print(log, contentType);
54+
}
55+
// else: message is lost with no warning
56+
```
57+
58+
### Failure Point C: CRLF line-ending differences on Windows
59+
60+
Windows uses CRLF. If the `OSProcessHandler` or the daemon JSON parser does not handle `\r\n` correctly, daemon messages may fail to parse, causing `app.log` events to be missed entirely. Less likely than A or B for JSON payloads, but worth ruling out.
61+
62+
## Where to Add the Fix
63+
64+
### Step 1: Locate daemon event registration
65+
66+
Find the method that registers `app.log` listeners — likely in `FlutterApp.java` in a method called after the app process starts (e.g., `onAppStarted`, `start`), or in the `LaunchState`/`FlutterLaunchTask` `execute()` override.
67+
68+
### Step 2: Register the listener unconditionally for all device types
69+
70+
```java
71+
daemonApi.listenForAppLog(appId, (String log, boolean isError) -> {
72+
ConsoleView console = getConsoleView();
73+
if (console == null) {
74+
logger.warn("FlutterApp: ConsoleView null on app.log for device: "
75+
+ device.deviceId());
76+
return;
77+
}
78+
console.print(log + "\n",
79+
isError ? ConsoleViewContentType.ERROR_OUTPUT
80+
: ConsoleViewContentType.NORMAL_OUTPUT);
81+
});
82+
```
83+
84+
Remove any `device.isWeb()` or `device.isMobile()` guard that wraps this registration.
85+
86+
### Step 3: Verify ConsoleView resolution for desktop
87+
88+
If the diagnostic log in Step 2 fires (console is null), trace how the `ConsoleView` is passed to `FlutterApp` for desktop vs. mobile/web configurations. The desktop run configuration likely takes a different code path during `RunContentDescriptor` creation and does not inject the console reference.
89+
90+
### Step 4: Cross-check the event name
91+
92+
Add a temporary catch-all to confirm what event names the Flutter tool actually emits on Windows:
93+
94+
```java
95+
daemonApi.listenForAllEvents(event -> {
96+
if (event.method.contains("log") || event.method.contains("error")) {
97+
logger.info("Daemon event: " + event.method + " / " + event.params);
98+
}
99+
});
100+
```
101+
102+
Check `idea.log` after triggering an exception on Windows to confirm the event name matches what the listener is registered for.
103+
104+
## Summary
105+
106+
| Component | Role | Failure risk on Windows |
107+
|---|---|---|
108+
| `FlutterLaunchTask.execute()` | Builds command, starts process | Low |
109+
| `OSProcessHandler` | Reads raw stdout/stderr | Medium (CRLF) |
110+
| `AppDaemonApi` / `app.log` listener | Forwards errors to console | **High — most likely root cause** |
111+
| `FlutterApp.getConsoleView()` | Resolves active `ConsoleView` | **High** |
112+
| `FlutterConsoleFilter` | Hyperlink post-processing | Low |
113+
114+
The most actionable fix is to audit where `app.log` daemon event listeners are registered, ensure registration is not gated on device type in a way that excludes desktop, and add null-safety diagnostics on the `ConsoleView` resolution path.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"eval_id": 1,
3+
"run_type": "without_skill",
4+
"expectations": [
5+
{
6+
"text": "Mentions ext.flutter.inspector.structuredErrors or structured errors being enabled as the reason Chrome differs from Windows",
7+
"passed": false,
8+
"evidence": "The response does not mention ext.flutter.inspector.structuredErrors or the structured errors extension at all. It incorrectly attributes the Chrome vs Windows difference to Chrome using stderr directly while Windows uses app.log daemon events, without identifying the actual structured errors mechanism."
9+
},
10+
{
11+
"text": "Mentions FlutterConsoleLogManager or handleFlutterErrorEvent as the handler for Flutter.Error events",
12+
"passed": false,
13+
"evidence": "The response does not mention FlutterConsoleLogManager or handleFlutterErrorEvent anywhere. It references DaemonApi, FlutterApp, and app.log listeners generically but never identifies the specific class responsible for handling Flutter.Error events."
14+
},
15+
{
16+
"text": "Identifies the silent exception catch (try/catch that only logs a warning) in processFlutterErrorEvent as the failure point",
17+
"passed": false,
18+
"evidence": "The response does not identify processFlutterErrorEvent or any silent catch block as the failure point. It speculates about an app.log listener not being registered for desktop targets or a null ConsoleView reference, which are hypothetical failure points not grounded in the actual code."
19+
},
20+
{
21+
"text": "Proposes a concrete fix \u00e2\u20ac\u201d either a fallback to display raw error text on exception, or adds error visibility when processFlutterErrorEvent throws",
22+
"passed": false,
23+
"evidence": "The response proposes registering an app.log listener unconditionally for all device types, which is not the actual fix needed. It does not address the real failure point (the silent catch in processFlutterErrorEvent) and does not propose adding fallback console output when an exception is thrown."
24+
},
25+
{
26+
"text": "Explains why Chrome works differently (extension not available on web, so app.log path is used instead)",
27+
"passed": false,
28+
"evidence": "The response incorrectly explains the Chrome difference as Chrome emitting errors directly to stderr of the flutter run process. It does not mention that the structuredErrors extension is unavailable on web, which is the actual reason the app.log path is used on Chrome."
29+
}
30+
],
31+
"summary": {
32+
"passed": 0,
33+
"failed": 5,
34+
"total": 5,
35+
"pass_rate": 0.0
36+
}
37+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"total_tokens": 26606,
3+
"duration_ms": 93572,
4+
"total_duration_seconds": 93.6
5+
}

0 commit comments

Comments
 (0)