flutter-devtools-mcp 0.3.1
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/LICENSE +21 -0
- package/README.md +208 -0
- package/README.zh-CN.md +292 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/services/ai-analysis.d.ts +6 -0
- package/dist/services/ai-analysis.d.ts.map +1 -0
- package/dist/services/ai-analysis.js +728 -0
- package/dist/services/ai-analysis.js.map +1 -0
- package/dist/services/collect-progress.d.ts +6 -0
- package/dist/services/collect-progress.d.ts.map +1 -0
- package/dist/services/collect-progress.js +23 -0
- package/dist/services/collect-progress.js.map +1 -0
- package/dist/services/cpu-profiler-service.d.ts +42 -0
- package/dist/services/cpu-profiler-service.d.ts.map +1 -0
- package/dist/services/cpu-profiler-service.js +208 -0
- package/dist/services/cpu-profiler-service.js.map +1 -0
- package/dist/services/cpu-symbol-filter.d.ts +10 -0
- package/dist/services/cpu-symbol-filter.d.ts.map +1 -0
- package/dist/services/cpu-symbol-filter.js +90 -0
- package/dist/services/cpu-symbol-filter.js.map +1 -0
- package/dist/services/http-profile-parser.d.ts +4 -0
- package/dist/services/http-profile-parser.d.ts.map +1 -0
- package/dist/services/http-profile-parser.js +71 -0
- package/dist/services/http-profile-parser.js.map +1 -0
- package/dist/services/json-parse-aggregate.d.ts +30 -0
- package/dist/services/json-parse-aggregate.d.ts.map +1 -0
- package/dist/services/json-parse-aggregate.js +155 -0
- package/dist/services/json-parse-aggregate.js.map +1 -0
- package/dist/services/network-aggregate.d.ts +50 -0
- package/dist/services/network-aggregate.d.ts.map +1 -0
- package/dist/services/network-aggregate.js +185 -0
- package/dist/services/network-aggregate.js.map +1 -0
- package/dist/services/network-capture-service.d.ts +50 -0
- package/dist/services/network-capture-service.d.ts.map +1 -0
- package/dist/services/network-capture-service.js +187 -0
- package/dist/services/network-capture-service.js.map +1 -0
- package/dist/services/network-capture.d.ts +2 -0
- package/dist/services/network-capture.d.ts.map +1 -0
- package/dist/services/network-capture.js +2 -0
- package/dist/services/network-capture.js.map +1 -0
- package/dist/services/performance-session.d.ts +41 -0
- package/dist/services/performance-session.d.ts.map +1 -0
- package/dist/services/performance-session.js +697 -0
- package/dist/services/performance-session.js.map +1 -0
- package/dist/services/performance-thresholds.d.ts +17 -0
- package/dist/services/performance-thresholds.d.ts.map +1 -0
- package/dist/services/performance-thresholds.js +19 -0
- package/dist/services/performance-thresholds.js.map +1 -0
- package/dist/services/profiler.d.ts +71 -0
- package/dist/services/profiler.d.ts.map +1 -0
- package/dist/services/profiler.js +314 -0
- package/dist/services/profiler.js.map +1 -0
- package/dist/services/rebuild-business-resolver.d.ts +24 -0
- package/dist/services/rebuild-business-resolver.d.ts.map +1 -0
- package/dist/services/rebuild-business-resolver.js +599 -0
- package/dist/services/rebuild-business-resolver.js.map +1 -0
- package/dist/services/rebuild-tracker-service.d.ts +45 -0
- package/dist/services/rebuild-tracker-service.d.ts.map +1 -0
- package/dist/services/rebuild-tracker-service.js +196 -0
- package/dist/services/rebuild-tracker-service.js.map +1 -0
- package/dist/services/session-types.d.ts +240 -0
- package/dist/services/session-types.d.ts.map +1 -0
- package/dist/services/session-types.js +180 -0
- package/dist/services/session-types.js.map +1 -0
- package/dist/services/threshold-alerts.d.ts +49 -0
- package/dist/services/threshold-alerts.d.ts.map +1 -0
- package/dist/services/threshold-alerts.js +258 -0
- package/dist/services/threshold-alerts.js.map +1 -0
- package/dist/services/timeline-cpu-parser.d.ts +28 -0
- package/dist/services/timeline-cpu-parser.d.ts.map +1 -0
- package/dist/services/timeline-cpu-parser.js +174 -0
- package/dist/services/timeline-cpu-parser.js.map +1 -0
- package/dist/services/timeline-extras.d.ts +61 -0
- package/dist/services/timeline-extras.d.ts.map +1 -0
- package/dist/services/timeline-extras.js +449 -0
- package/dist/services/timeline-extras.js.map +1 -0
- package/dist/services/vm-service-client.d.ts +123 -0
- package/dist/services/vm-service-client.d.ts.map +1 -0
- package/dist/services/vm-service-client.js +418 -0
- package/dist/services/vm-service-client.js.map +1 -0
- package/dist/tools/connection.d.ts +4 -0
- package/dist/tools/connection.d.ts.map +1 -0
- package/dist/tools/connection.js +127 -0
- package/dist/tools/connection.js.map +1 -0
- package/dist/tools/debug-actions.d.ts +4 -0
- package/dist/tools/debug-actions.d.ts.map +1 -0
- package/dist/tools/debug-actions.js +210 -0
- package/dist/tools/debug-actions.js.map +1 -0
- package/dist/tools/discover.d.ts +4 -0
- package/dist/tools/discover.d.ts.map +1 -0
- package/dist/tools/discover.js +183 -0
- package/dist/tools/discover.js.map +1 -0
- package/dist/tools/memory.d.ts +4 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +145 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/network.d.ts +4 -0
- package/dist/tools/network.d.ts.map +1 -0
- package/dist/tools/network.js +265 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/performance-session.d.ts +4 -0
- package/dist/tools/performance-session.d.ts.map +1 -0
- package/dist/tools/performance-session.js +105 -0
- package/dist/tools/performance-session.js.map +1 -0
- package/dist/tools/profiling.d.ts +5 -0
- package/dist/tools/profiling.d.ts.map +1 -0
- package/dist/tools/profiling.js +142 -0
- package/dist/tools/profiling.js.map +1 -0
- package/dist/tools/rebuild-tracker.d.ts +4 -0
- package/dist/tools/rebuild-tracker.d.ts.map +1 -0
- package/dist/tools/rebuild-tracker.js +228 -0
- package/dist/tools/rebuild-tracker.js.map +1 -0
- package/dist/tools/snapshot-diff.d.ts +4 -0
- package/dist/tools/snapshot-diff.d.ts.map +1 -0
- package/dist/tools/snapshot-diff.js +235 -0
- package/dist/tools/snapshot-diff.js.map +1 -0
- package/dist/tools/widget-tree.d.ts +4 -0
- package/dist/tools/widget-tree.d.ts.map +1 -0
- package/dist/tools/widget-tree.js +156 -0
- package/dist/tools/widget-tree.js.map +1 -0
- package/docs/README.md +9 -0
- package/docs/performance-audit-requirements.md +403 -0
- package/docs/performance-metrics-guide.md +207 -0
- package/docs/performance-session-simple-design.md +399 -0
- package/examples/app_network_image.dart +242 -0
- package/examples/app_network_image_README.md +51 -0
- package/package.json +69 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import 'dart:async';
|
|
2
|
+
import 'dart:developer' as developer;
|
|
3
|
+
import 'dart:io';
|
|
4
|
+
import 'dart:typed_data';
|
|
5
|
+
import 'dart:ui' as ui;
|
|
6
|
+
|
|
7
|
+
import 'package:flutter/foundation.dart';
|
|
8
|
+
import 'package:flutter/material.dart';
|
|
9
|
+
|
|
10
|
+
/// 业务侧「一处侵入」样板:统一网络图入口,供 flutter-devtools-mcp 采集
|
|
11
|
+
/// `imageDecode` 时带上 url / 尺寸 / 字节数。
|
|
12
|
+
///
|
|
13
|
+
/// ## 接入步骤
|
|
14
|
+
/// 1. 复制本文件到业务工程(如 `lib/widgets/app_network_image.dart`)
|
|
15
|
+
/// 2. 全站网络图改用 [AppNetworkImage],禁止业务直接 `Image.network`
|
|
16
|
+
/// 3. 大图预加载/强制解码走 [AppImageLoader.loadAndDecode]
|
|
17
|
+
///
|
|
18
|
+
/// ## Timeline 约定(MCP 已识别)
|
|
19
|
+
/// - 事件名:`app.imageDecode`
|
|
20
|
+
/// - arguments:`url`(必填)、`ms`(必填,Stopwatch 耗时)、`width`/`height`/`bytes`(可选)
|
|
21
|
+
///
|
|
22
|
+
/// 复制到业务后可按需换成 Dio / cached_network_image,只要保留 Timeline 字段即可。
|
|
23
|
+
class AppImageLoader {
|
|
24
|
+
AppImageLoader._();
|
|
25
|
+
|
|
26
|
+
static const String timelineEvent = 'app.imageDecode';
|
|
27
|
+
|
|
28
|
+
/// 下载并解码;耗时与元数据写入 Timeline,便于性能报告点名 URL。
|
|
29
|
+
///
|
|
30
|
+
/// 注意:跨 await 时 Timeline B/E 时常采不到时长,因此用 Stopwatch
|
|
31
|
+
/// 在结束 instant 里写入 `ms`,供 MCP 解析。
|
|
32
|
+
static Future<ui.Image> loadAndDecode(
|
|
33
|
+
String url, {
|
|
34
|
+
int? cacheWidth,
|
|
35
|
+
int? cacheHeight,
|
|
36
|
+
}) async {
|
|
37
|
+
final sw = Stopwatch()..start();
|
|
38
|
+
try {
|
|
39
|
+
final bytes = await _downloadBytes(url);
|
|
40
|
+
final codec = await ui.instantiateImageCodec(
|
|
41
|
+
bytes,
|
|
42
|
+
targetWidth: cacheWidth,
|
|
43
|
+
targetHeight: cacheHeight,
|
|
44
|
+
);
|
|
45
|
+
final frame = await codec.getNextFrame();
|
|
46
|
+
return frame.image;
|
|
47
|
+
} finally {
|
|
48
|
+
sw.stop();
|
|
49
|
+
developer.Timeline.instantSync(
|
|
50
|
+
timelineEvent,
|
|
51
|
+
arguments: <Object, Object>{
|
|
52
|
+
'url': url,
|
|
53
|
+
'ms': sw.elapsedMilliseconds,
|
|
54
|
+
if (cacheWidth != null) 'width': cacheWidth,
|
|
55
|
+
if (cacheHeight != null) 'height': cacheHeight,
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static Future<Uint8List> _downloadBytes(String url) async {
|
|
62
|
+
final client = HttpClient();
|
|
63
|
+
try {
|
|
64
|
+
final req = await client.getUrl(Uri.parse(url));
|
|
65
|
+
final res = await req.close();
|
|
66
|
+
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
67
|
+
throw HttpException('HTTP ${res.statusCode}', uri: Uri.parse(url));
|
|
68
|
+
}
|
|
69
|
+
final builder = BytesBuilder(copy: false);
|
|
70
|
+
await for (final chunk in res) {
|
|
71
|
+
builder.add(chunk);
|
|
72
|
+
}
|
|
73
|
+
return builder.takeBytes();
|
|
74
|
+
} finally {
|
|
75
|
+
client.close(force: true);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// 带 Timeline 埋点的 [ImageProvider],供 [AppNetworkImage] 使用。
|
|
81
|
+
class AppNetworkImageProvider extends ImageProvider<AppNetworkImageProvider> {
|
|
82
|
+
const AppNetworkImageProvider(
|
|
83
|
+
this.url, {
|
|
84
|
+
this.cacheWidth,
|
|
85
|
+
this.cacheHeight,
|
|
86
|
+
this.scale = 1.0,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
final String url;
|
|
90
|
+
final int? cacheWidth;
|
|
91
|
+
final int? cacheHeight;
|
|
92
|
+
final double scale;
|
|
93
|
+
|
|
94
|
+
@override
|
|
95
|
+
Future<AppNetworkImageProvider> obtainKey(ImageConfiguration configuration) {
|
|
96
|
+
return SynchronousFuture<AppNetworkImageProvider>(this);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@override
|
|
100
|
+
ImageStreamCompleter loadImage(
|
|
101
|
+
AppNetworkImageProvider key,
|
|
102
|
+
ImageDecoderCallback decode,
|
|
103
|
+
) {
|
|
104
|
+
final chunkEvents = StreamController<ImageChunkEvent>();
|
|
105
|
+
return MultiFrameImageStreamCompleter(
|
|
106
|
+
codec: _loadAsync(key, chunkEvents, decode),
|
|
107
|
+
scale: key.scale,
|
|
108
|
+
chunkEvents: chunkEvents.stream,
|
|
109
|
+
informationCollector: () => <DiagnosticsNode>[
|
|
110
|
+
DiagnosticsProperty<ImageProvider>('Image provider', this),
|
|
111
|
+
DiagnosticsProperty<String>('URL', url),
|
|
112
|
+
],
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
Future<ui.Codec> _loadAsync(
|
|
117
|
+
AppNetworkImageProvider key,
|
|
118
|
+
StreamController<ImageChunkEvent> chunkEvents,
|
|
119
|
+
ImageDecoderCallback decode,
|
|
120
|
+
) async {
|
|
121
|
+
final sw = Stopwatch()..start();
|
|
122
|
+
try {
|
|
123
|
+
final bytes = await AppImageLoader._downloadBytes(key.url);
|
|
124
|
+
chunkEvents.add(
|
|
125
|
+
ImageChunkEvent(
|
|
126
|
+
cumulativeBytesLoaded: bytes.length,
|
|
127
|
+
expectedTotalBytes: bytes.length,
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
|
131
|
+
return decode(
|
|
132
|
+
buffer,
|
|
133
|
+
getTargetSize: (intrinsicWidth, intrinsicHeight) {
|
|
134
|
+
return ui.TargetImageSize(
|
|
135
|
+
width: key.cacheWidth,
|
|
136
|
+
height: key.cacheHeight,
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
} catch (e, st) {
|
|
141
|
+
scheduleMicrotask(() {
|
|
142
|
+
chunkEvents.addError(e, st);
|
|
143
|
+
});
|
|
144
|
+
rethrow;
|
|
145
|
+
} finally {
|
|
146
|
+
sw.stop();
|
|
147
|
+
developer.Timeline.instantSync(
|
|
148
|
+
AppImageLoader.timelineEvent,
|
|
149
|
+
arguments: <Object, Object>{
|
|
150
|
+
'url': key.url,
|
|
151
|
+
'ms': sw.elapsedMilliseconds,
|
|
152
|
+
if (key.cacheWidth != null) 'width': key.cacheWidth!,
|
|
153
|
+
if (key.cacheHeight != null) 'height': key.cacheHeight!,
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
await chunkEvents.close();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@override
|
|
161
|
+
bool operator ==(Object other) {
|
|
162
|
+
if (other.runtimeType != runtimeType) return false;
|
|
163
|
+
return other is AppNetworkImageProvider &&
|
|
164
|
+
other.url == url &&
|
|
165
|
+
other.cacheWidth == cacheWidth &&
|
|
166
|
+
other.cacheHeight == cacheHeight &&
|
|
167
|
+
other.scale == scale;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@override
|
|
171
|
+
int get hashCode => Object.hash(url, cacheWidth, cacheHeight, scale);
|
|
172
|
+
|
|
173
|
+
@override
|
|
174
|
+
String toString() =>
|
|
175
|
+
'${objectRuntimeType(this, 'AppNetworkImageProvider')}("$url")';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// 业务推荐使用的网络图组件(替代裸 [Image.network])。
|
|
179
|
+
class AppNetworkImage extends StatelessWidget {
|
|
180
|
+
const AppNetworkImage({
|
|
181
|
+
super.key,
|
|
182
|
+
required this.url,
|
|
183
|
+
this.width,
|
|
184
|
+
this.height,
|
|
185
|
+
this.fit = BoxFit.cover,
|
|
186
|
+
this.cacheWidth,
|
|
187
|
+
this.cacheHeight,
|
|
188
|
+
this.errorBuilder,
|
|
189
|
+
this.placeholder,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
final String url;
|
|
193
|
+
final double? width;
|
|
194
|
+
final double? height;
|
|
195
|
+
final BoxFit fit;
|
|
196
|
+
|
|
197
|
+
/// 解码目标宽高(逻辑像素×devicePixelRatio 由调用方换算,或直接传展示像素)
|
|
198
|
+
final int? cacheWidth;
|
|
199
|
+
final int? cacheHeight;
|
|
200
|
+
|
|
201
|
+
final ImageErrorWidgetBuilder? errorBuilder;
|
|
202
|
+
final Widget? placeholder;
|
|
203
|
+
|
|
204
|
+
@override
|
|
205
|
+
Widget build(BuildContext context) {
|
|
206
|
+
final dpr = MediaQuery.devicePixelRatioOf(context);
|
|
207
|
+
final tw = cacheWidth ??
|
|
208
|
+
(width != null ? (width! * dpr).round() : null);
|
|
209
|
+
final th = cacheHeight ??
|
|
210
|
+
(height != null ? (height! * dpr).round() : null);
|
|
211
|
+
|
|
212
|
+
return Image(
|
|
213
|
+
image: AppNetworkImageProvider(url, cacheWidth: tw, cacheHeight: th),
|
|
214
|
+
width: width,
|
|
215
|
+
height: height,
|
|
216
|
+
fit: fit,
|
|
217
|
+
gaplessPlayback: true,
|
|
218
|
+
errorBuilder: errorBuilder ??
|
|
219
|
+
(context, error, stackTrace) => SizedBox(
|
|
220
|
+
width: width,
|
|
221
|
+
height: height,
|
|
222
|
+
child: placeholder ??
|
|
223
|
+
const Center(child: Icon(Icons.broken_image, size: 20)),
|
|
224
|
+
),
|
|
225
|
+
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
|
|
226
|
+
if (wasSynchronouslyLoaded || frame != null) return child;
|
|
227
|
+
return SizedBox(
|
|
228
|
+
width: width,
|
|
229
|
+
height: height,
|
|
230
|
+
child: placeholder ??
|
|
231
|
+
const Center(
|
|
232
|
+
child: SizedBox(
|
|
233
|
+
width: 16,
|
|
234
|
+
height: 16,
|
|
235
|
+
child: CircularProgressIndicator(strokeWidth: 2),
|
|
236
|
+
),
|
|
237
|
+
),
|
|
238
|
+
);
|
|
239
|
+
},
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# AppNetworkImage — 业务接入样板
|
|
2
|
+
|
|
3
|
+
复制 `flutter-simple/lib/perf/app_network_image.dart` 到业务工程,用于让性能采集能拿到 **图片 URL / 尺寸 / 字节数**。
|
|
4
|
+
|
|
5
|
+
## 为什么要这一处侵入
|
|
6
|
+
|
|
7
|
+
| 方式 | 有无 URL | 说明 |
|
|
8
|
+
|------|----------|------|
|
|
9
|
+
| 纯 Timeline 引擎事件 | 通常无 | 只能告警「有慢解码」 |
|
|
10
|
+
| **统一 `AppNetworkImage`** | 有 | 报告可点名具体图 |
|
|
11
|
+
|
|
12
|
+
## 接入
|
|
13
|
+
|
|
14
|
+
1. 复制文件到例如 `lib/widgets/app_network_image.dart`
|
|
15
|
+
2. 列表/头像/封面改为:
|
|
16
|
+
|
|
17
|
+
```dart
|
|
18
|
+
AppNetworkImage(
|
|
19
|
+
url: item.coverUrl,
|
|
20
|
+
width: 56,
|
|
21
|
+
height: 56,
|
|
22
|
+
fit: BoxFit.cover,
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. 预加载 / 强制解码:
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
final image = await AppImageLoader.loadAndDecode(
|
|
30
|
+
url,
|
|
31
|
+
cacheWidth: 800,
|
|
32
|
+
cacheHeight: 600,
|
|
33
|
+
);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
4. (可选)lint / Code Review:禁止业务直接 `Image.network`
|
|
37
|
+
|
|
38
|
+
## Timeline 约定
|
|
39
|
+
|
|
40
|
+
- 事件名:`app.imageDecode`
|
|
41
|
+
- arguments:`url`(必填),`ms`(必填,Stopwatch 耗时),`width` / `height` / `bytes`(可选)
|
|
42
|
+
|
|
43
|
+
跨 `await` 时 Timeline 的 B/E 时常采不到时长,样板用 **Stopwatch + instantSync 写入 `ms`**,MCP 优先读该字段。
|
|
44
|
+
|
|
45
|
+
`flutter-devtools-mcp` 的 `imageDecode` 指标会解析这些字段,并在报告「慢解码」中展示链接。
|
|
46
|
+
|
|
47
|
+
指标解读见:[../docs/performance-metrics-guide.md](../docs/performance-metrics-guide.md) §5。
|
|
48
|
+
|
|
49
|
+
## 与 cached_network_image
|
|
50
|
+
|
|
51
|
+
可在现有缓存库外包一层,在真正 decode 结束后用 Stopwatch 打同样的 `Timeline.instantSync(app.imageDecode, arguments: {url, ms, ...})` 即可,不必换掉缓存策略。
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "flutter-devtools-mcp",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "MCP server that connects AI agents to Flutter DevTools for runtime inspection, profiling, and debugging of Flutter applications",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"flutter-devtools-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"README.zh-CN.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"docs",
|
|
16
|
+
"examples"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"dev": "tsx src/index.ts",
|
|
22
|
+
"prepublishOnly": "npm run build",
|
|
23
|
+
"test:regression": "node scripts/regression-performance-session.mjs",
|
|
24
|
+
"test:regression:spawn": "node scripts/regression-performance-session.mjs --spawn",
|
|
25
|
+
"test:regression:android": "FLUTTER_DEVICE=android node scripts/regression-performance-session.mjs --spawn",
|
|
26
|
+
"test:regression:android:profile": "FLUTTER_DEVICE=android FLUTTER_RUN_MODE=profile node scripts/regression-performance-session.mjs --spawn",
|
|
27
|
+
"test:regression:android:profile:30s": "FLUTTER_DEVICE=android FLUTTER_RUN_MODE=profile REGRESSION_DURATION_SEC=30 node scripts/regression-performance-session.mjs --spawn",
|
|
28
|
+
"test:regression:ios": "FLUTTER_DEVICE=ios node scripts/regression-performance-session.mjs --spawn",
|
|
29
|
+
"prepare": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"flutter",
|
|
33
|
+
"devtools",
|
|
34
|
+
"mcp",
|
|
35
|
+
"model-context-protocol",
|
|
36
|
+
"ai",
|
|
37
|
+
"debugging",
|
|
38
|
+
"profiling",
|
|
39
|
+
"dart",
|
|
40
|
+
"vm-service",
|
|
41
|
+
"cursor",
|
|
42
|
+
"claude"
|
|
43
|
+
],
|
|
44
|
+
"author": "treexi",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/treexi/flutter-devtools-ext.git",
|
|
49
|
+
"directory": "flutter-devtools-mcp"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/treexi/flutter-devtools-ext/issues"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/treexi/flutter-devtools-ext/tree/main/flutter-devtools-mcp#readme",
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18.0.0"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
60
|
+
"ws": "^8.18.1",
|
|
61
|
+
"zod": "^3.24.2"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/node": "^22.13.9",
|
|
65
|
+
"@types/ws": "^8.18.0",
|
|
66
|
+
"tsx": "^4.19.3",
|
|
67
|
+
"typescript": "^5.8.2"
|
|
68
|
+
}
|
|
69
|
+
}
|