@uwa4d/openapi-mcp 0.2.0-beta.0 → 0.2.0-beta.10
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/README.md +105 -9
- package/dist/annotate-dashboard.d.ts +48 -0
- package/dist/annotate-dashboard.js +413 -0
- package/dist/cli.js +29 -6
- package/dist/client.js +4 -13
- package/dist/composite/helpers.d.ts +19 -0
- package/dist/composite/helpers.js +90 -0
- package/dist/composite/index.d.ts +25 -0
- package/dist/composite/index.js +46 -0
- package/dist/composite/name-pattern.d.ts +8 -0
- package/dist/composite/name-pattern.js +25 -0
- package/dist/composite/overview-view.d.ts +33 -0
- package/dist/composite/overview-view.js +373 -0
- package/dist/composite/report-diagnosis.d.ts +2 -0
- package/dist/composite/report-diagnosis.js +347 -0
- package/dist/composite/route-overview.d.ts +72 -0
- package/dist/composite/route-overview.js +233 -0
- package/dist/composite/stack-agg.d.ts +77 -0
- package/dist/composite/stack-agg.js +409 -0
- package/dist/composite/stack-test-mode.d.ts +33 -0
- package/dist/composite/stack-test-mode.js +60 -0
- package/dist/composite/top-functions.d.ts +21 -0
- package/dist/composite/top-functions.js +178 -0
- package/dist/composite/top-resources.d.ts +12 -0
- package/dist/composite/top-resources.js +263 -0
- package/dist/composite/types.d.ts +25 -0
- package/dist/composite/types.js +2 -0
- package/dist/error-hints.d.ts +23 -0
- package/dist/error-hints.js +80 -0
- package/dist/indicator-dashboard-keys.d.ts +12 -0
- package/dist/indicator-dashboard-keys.js +50 -0
- package/dist/indicator-dashboard-keys.json +338 -0
- package/dist/presets.js +9 -0
- package/dist/server-instructions.d.ts +5 -0
- package/dist/server-instructions.js +17 -0
- package/dist/server.d.ts +6 -1
- package/dist/server.js +33 -5
- package/dist/tools.d.ts +17 -0
- package/dist/tools.js +399 -18
- package/dist/version-check.d.ts +14 -0
- package/dist/version-check.js +94 -0
- package/dist/version-guide.d.ts +19 -0
- package/dist/version-guide.js +223 -0
- package/package.json +2 -2
- package/spec/overrides.json +26 -0
- package/spec/uwa-openapi.json +495 -111
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { isObj } from './helpers.js';
|
|
2
|
+
function firstVal(v) {
|
|
3
|
+
return Array.isArray(v) ? v[0] : v;
|
|
4
|
+
}
|
|
5
|
+
function numOf(v) {
|
|
6
|
+
const x = firstVal(v);
|
|
7
|
+
if (typeof x === 'number' && Number.isFinite(x))
|
|
8
|
+
return x;
|
|
9
|
+
if (typeof x === 'string' && x.trim() && !Number.isNaN(Number(x)))
|
|
10
|
+
return Number(x);
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function toBytes(value, unit) {
|
|
14
|
+
const u = (unit ?? '').toLowerCase();
|
|
15
|
+
if (u === 'b' || u === 'byte' || u === 'bytes')
|
|
16
|
+
return Math.round(value);
|
|
17
|
+
if (u === 'kb')
|
|
18
|
+
return Math.round(value * 1024);
|
|
19
|
+
if (u === 'mb')
|
|
20
|
+
return Math.round(value * 1024 * 1024);
|
|
21
|
+
if (u === 'gb')
|
|
22
|
+
return Math.round(value * 1024 * 1024 * 1024);
|
|
23
|
+
// 无单位时:很大的数当字节,否则当 MB(兼容 v1 brief 的 _mem_max_mb)
|
|
24
|
+
return value > 10_000 ? Math.round(value) : Math.round(value * 1024 * 1024);
|
|
25
|
+
}
|
|
26
|
+
function unitFromLabel(label) {
|
|
27
|
+
const m = /[((]\s*(MB|KB|GB|B|字节)\s*[))]/i.exec(label);
|
|
28
|
+
return m?.[1]?.toLowerCase() === '字节' ? 'b' : m?.[1]?.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
/** 排除「数量峰值」这类非内存指标。 */
|
|
31
|
+
function looksLikeMemoryMetric(label, key, unit) {
|
|
32
|
+
if (/数量|count|cnt/i.test(label) || /count|cnt/i.test(key))
|
|
33
|
+
return false;
|
|
34
|
+
if (/^(b|byte|bytes|kb|mb|gb)$/i.test(unit))
|
|
35
|
+
return true;
|
|
36
|
+
return /内存|memory|mem|reserved|used|heap|gfx|mono|lua/i.test(label + key);
|
|
37
|
+
}
|
|
38
|
+
function guessAssetType(label, fallback) {
|
|
39
|
+
const rules = [
|
|
40
|
+
[/RenderTexture/i, 'RenderTexture'],
|
|
41
|
+
[/纹理|Texture/i, 'Texture'],
|
|
42
|
+
[/网格|Mesh/i, 'Mesh'],
|
|
43
|
+
[/Shader/i, 'Shader'],
|
|
44
|
+
[/材质|Material/i, 'Material'],
|
|
45
|
+
[/动画|Animation/i, 'AnimationClip'],
|
|
46
|
+
[/音频|Audio/i, 'AudioClip'],
|
|
47
|
+
[/字体|Font/i, 'Font'],
|
|
48
|
+
[/AssetBundle/i, 'AssetBundle'],
|
|
49
|
+
[/TextAsset|文本资源/i, 'TextAsset'],
|
|
50
|
+
[/粒子|Particle/i, 'ParticleSystem'],
|
|
51
|
+
[/Lua/i, 'Lua'],
|
|
52
|
+
[/Mono/i, 'Mono'],
|
|
53
|
+
[/Gfx/i, 'Gfx'],
|
|
54
|
+
];
|
|
55
|
+
for (const [re, t] of rules)
|
|
56
|
+
if (re.test(label))
|
|
57
|
+
return t;
|
|
58
|
+
return fallback;
|
|
59
|
+
}
|
|
60
|
+
/** 把 summary / UE brief 一类 [{label,value}] 展开成 map。 */
|
|
61
|
+
function expandLabelValueRows(rows) {
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const row of rows) {
|
|
64
|
+
if (!isObj(row))
|
|
65
|
+
continue;
|
|
66
|
+
const label = String(row['label'] ?? row['key'] ?? '');
|
|
67
|
+
if (!label)
|
|
68
|
+
continue;
|
|
69
|
+
out[label] = firstVal(row['value'] ?? row['data']);
|
|
70
|
+
const key = row['key'];
|
|
71
|
+
if (typeof key === 'string' && key && !(key in out))
|
|
72
|
+
out[key] = out[label];
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
function basicInfoMap(basicInfo) {
|
|
77
|
+
const out = {};
|
|
78
|
+
if (!basicInfo)
|
|
79
|
+
return out;
|
|
80
|
+
const rows = Array.isArray(basicInfo)
|
|
81
|
+
? basicInfo
|
|
82
|
+
: isObj(basicInfo)
|
|
83
|
+
? Object.values(basicInfo)
|
|
84
|
+
: [];
|
|
85
|
+
for (const row of rows) {
|
|
86
|
+
if (!isObj(row))
|
|
87
|
+
continue;
|
|
88
|
+
const key = String(row['key'] ?? row['label'] ?? '');
|
|
89
|
+
if (!key)
|
|
90
|
+
continue;
|
|
91
|
+
out[key] = firstVal(row['data'] ?? row['value']);
|
|
92
|
+
const label = row['label'];
|
|
93
|
+
if (typeof label === 'string' && label && !(label in out))
|
|
94
|
+
out[label] = out[key];
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
function parseHasResource(summary, brief) {
|
|
99
|
+
for (const src of [brief, summary]) {
|
|
100
|
+
for (const [k, v] of Object.entries(src)) {
|
|
101
|
+
const keyHit = /^(OverviewHasResource|Resource|resourceMemory|resourceManagement|资源内存|资源管理|资源采集)$/i.test(k);
|
|
102
|
+
if (!keyHit)
|
|
103
|
+
continue;
|
|
104
|
+
const n = numOf(v);
|
|
105
|
+
if (n != null)
|
|
106
|
+
return n !== 0;
|
|
107
|
+
const s = String(firstVal(v) ?? '');
|
|
108
|
+
if (s === '1' || s === '2' || /详细|开启|千帧|60|模式/.test(s))
|
|
109
|
+
return true;
|
|
110
|
+
if (s === '0' || /关闭|无|关/.test(s))
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* UE 2.0:从 Resource / resource 段判定资源采集。
|
|
118
|
+
* 「资源内存占用峰值」> 0 → true;段存在但无法确认时返回 null(不误报关闭)。
|
|
119
|
+
*/
|
|
120
|
+
function parseHasResourceFromResourceSection(report) {
|
|
121
|
+
const section = report['Resource'] ?? report['resource'];
|
|
122
|
+
if (!Array.isArray(section) || section.length === 0)
|
|
123
|
+
return null;
|
|
124
|
+
let peak = null;
|
|
125
|
+
let anyMemPositive = false;
|
|
126
|
+
for (const item of section) {
|
|
127
|
+
if (!isObj(item))
|
|
128
|
+
continue;
|
|
129
|
+
const label = String(item['label'] ?? item['key'] ?? '');
|
|
130
|
+
const n = numOf(item['value'] ?? item['data']);
|
|
131
|
+
if (n == null)
|
|
132
|
+
continue;
|
|
133
|
+
if (/^资源内存占用峰值/.test(label) || /资源内存占用峰值(MB)/.test(label))
|
|
134
|
+
peak = n;
|
|
135
|
+
const unit = unitFromLabel(label) ?? '';
|
|
136
|
+
if (looksLikeMemoryMetric(label, '', unit) && n > 0)
|
|
137
|
+
anyMemPositive = true;
|
|
138
|
+
}
|
|
139
|
+
if (peak != null && peak > 0)
|
|
140
|
+
return true;
|
|
141
|
+
if (anyMemPositive)
|
|
142
|
+
return true;
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
/** 解析 Resource / resource 数组 → memory[](排除数量峰值)。 */
|
|
146
|
+
function memoryFromResourceSection(report) {
|
|
147
|
+
const section = report['Resource'] ?? report['resource'];
|
|
148
|
+
if (!Array.isArray(section))
|
|
149
|
+
return [];
|
|
150
|
+
const memory = [];
|
|
151
|
+
for (const item of section) {
|
|
152
|
+
if (!isObj(item))
|
|
153
|
+
continue;
|
|
154
|
+
const label = String(item['label'] ?? item['key'] ?? '');
|
|
155
|
+
const num = numOf(item['value'] ?? item['data']);
|
|
156
|
+
if (!label || num == null)
|
|
157
|
+
continue;
|
|
158
|
+
const unit = unitFromLabel(label) ?? 'mb';
|
|
159
|
+
if (!looksLikeMemoryMetric(label, '', unit))
|
|
160
|
+
continue;
|
|
161
|
+
// 总「资源内存占用峰值」不绑具体类型,仍保留便于看总量
|
|
162
|
+
memory.push({
|
|
163
|
+
name: label,
|
|
164
|
+
assetType: guessAssetType(label, 'Resource'),
|
|
165
|
+
memoryBytes: toBytes(num, unit),
|
|
166
|
+
_source: 'overview.Resource',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return memory;
|
|
170
|
+
}
|
|
171
|
+
function extractV2(data) {
|
|
172
|
+
const summary = basicInfoMap(data['basicInfo']);
|
|
173
|
+
const brief = {};
|
|
174
|
+
const functions = [];
|
|
175
|
+
const memory = [];
|
|
176
|
+
const categories = Array.isArray(data['categories']) ? data['categories'] : [];
|
|
177
|
+
for (const cat of categories) {
|
|
178
|
+
if (!isObj(cat))
|
|
179
|
+
continue;
|
|
180
|
+
const catName = String(cat['category'] ?? '');
|
|
181
|
+
const indicators = Array.isArray(cat['indicators']) ? cat['indicators'] : [];
|
|
182
|
+
for (const ind of indicators) {
|
|
183
|
+
if (!isObj(ind))
|
|
184
|
+
continue;
|
|
185
|
+
const label = String(ind['label'] ?? ind['key'] ?? '');
|
|
186
|
+
const key = String(ind['key'] ?? ind['indicatorKey'] ?? label);
|
|
187
|
+
const value = numOf(ind['data'] ?? ind['value']);
|
|
188
|
+
const unitObj = ind['unit'];
|
|
189
|
+
const unit = isObj(unitObj) ? String(unitObj['value'] ?? unitObj['description'] ?? '') : String(unitObj ?? '');
|
|
190
|
+
if (value != null && key)
|
|
191
|
+
brief[key] = value;
|
|
192
|
+
if (value != null && label && !(label in brief))
|
|
193
|
+
brief[label] = value;
|
|
194
|
+
const isFuncCat = /卡顿|重点函数|函数/.test(catName);
|
|
195
|
+
const isMemCat = /内存|资源|LLM/i.test(catName);
|
|
196
|
+
if (isFuncCat && value != null && label) {
|
|
197
|
+
functions.push({
|
|
198
|
+
name: label,
|
|
199
|
+
value,
|
|
200
|
+
unit: unit || undefined,
|
|
201
|
+
source: `overview.v2.${catName}`,
|
|
202
|
+
label: catName,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (isMemCat && value != null && label && looksLikeMemoryMetric(label, key, unit)) {
|
|
206
|
+
memory.push({
|
|
207
|
+
name: label,
|
|
208
|
+
assetType: guessAssetType(label, catName),
|
|
209
|
+
memoryBytes: toBytes(value, unit),
|
|
210
|
+
_source: `overview.v2.${catName}`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
functions.sort((a, b) => b.value - a.value);
|
|
216
|
+
memory.sort((a, b) => b.memoryBytes - a.memoryBytes);
|
|
217
|
+
return {
|
|
218
|
+
brief,
|
|
219
|
+
summary,
|
|
220
|
+
functions,
|
|
221
|
+
memory,
|
|
222
|
+
hasResource: parseHasResource(summary, brief),
|
|
223
|
+
shape: 'v2',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function extractV1OrUe(report) {
|
|
227
|
+
const brief = {};
|
|
228
|
+
const summary = {};
|
|
229
|
+
const functions = [];
|
|
230
|
+
const memory = [];
|
|
231
|
+
const briefIsArray = Array.isArray(report['brief']);
|
|
232
|
+
if (briefIsArray) {
|
|
233
|
+
Object.assign(brief, expandLabelValueRows(report['brief']));
|
|
234
|
+
}
|
|
235
|
+
else if (isObj(report['brief'])) {
|
|
236
|
+
for (const [k, v] of Object.entries(report['brief']))
|
|
237
|
+
brief[k] = firstVal(v);
|
|
238
|
+
}
|
|
239
|
+
if (Array.isArray(report['summary'])) {
|
|
240
|
+
Object.assign(summary, expandLabelValueRows(report['summary']));
|
|
241
|
+
}
|
|
242
|
+
else if (isObj(report['reportInfo'])) {
|
|
243
|
+
Object.assign(summary, report['reportInfo']);
|
|
244
|
+
}
|
|
245
|
+
if (Array.isArray(report['func'])) {
|
|
246
|
+
for (const item of report['func']) {
|
|
247
|
+
if (!isObj(item))
|
|
248
|
+
continue;
|
|
249
|
+
const name = String(item['label'] ?? item['key'] ?? item['name'] ?? '');
|
|
250
|
+
const value = numOf(item['value'] ?? item['data']);
|
|
251
|
+
if (!name || value == null)
|
|
252
|
+
continue;
|
|
253
|
+
functions.push({ name, value, source: 'overview.func', label: name });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (isObj(report['brief'])) {
|
|
257
|
+
for (const [k, v] of Object.entries(report['brief'])) {
|
|
258
|
+
if (!/_mem_max_mb$/i.test(k) && !/Memory.*max/i.test(k))
|
|
259
|
+
continue;
|
|
260
|
+
const num = numOf(v);
|
|
261
|
+
if (num == null)
|
|
262
|
+
continue;
|
|
263
|
+
memory.push({
|
|
264
|
+
name: k,
|
|
265
|
+
assetType: k.replace(/_mem_max_mb$/i, ''),
|
|
266
|
+
memoryBytes: toBytes(num, 'mb'),
|
|
267
|
+
_source: 'overview.brief',
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// UE 数组 brief 里也可能夹带内存类指标(类型级)
|
|
272
|
+
if (briefIsArray) {
|
|
273
|
+
for (const [label, v] of Object.entries(brief)) {
|
|
274
|
+
if (!looksLikeMemoryMetric(label, '', unitFromLabel(label) ?? ''))
|
|
275
|
+
continue;
|
|
276
|
+
const num = numOf(v);
|
|
277
|
+
if (num == null)
|
|
278
|
+
continue;
|
|
279
|
+
if (memory.some((m) => m.name === label))
|
|
280
|
+
continue;
|
|
281
|
+
memory.push({
|
|
282
|
+
name: label,
|
|
283
|
+
assetType: guessAssetType(label, 'brief'),
|
|
284
|
+
memoryBytes: toBytes(num, unitFromLabel(label) ?? 'mb'),
|
|
285
|
+
_source: 'overview.brief',
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
for (const row of memoryFromResourceSection(report)) {
|
|
290
|
+
if (memory.some((m) => m.name === row.name))
|
|
291
|
+
continue;
|
|
292
|
+
memory.push(row);
|
|
293
|
+
}
|
|
294
|
+
if (Array.isArray(report['asset_stats'])) {
|
|
295
|
+
for (const item of report['asset_stats']) {
|
|
296
|
+
if (!isObj(item))
|
|
297
|
+
continue;
|
|
298
|
+
const label = String(item['label'] ?? item['key'] ?? '');
|
|
299
|
+
const num = numOf(item['value'] ?? item['data']);
|
|
300
|
+
if (!label || num == null)
|
|
301
|
+
continue;
|
|
302
|
+
if (memory.some((m) => m.name === label))
|
|
303
|
+
continue;
|
|
304
|
+
const looksMb = /mb|内存/i.test(label);
|
|
305
|
+
memory.push({
|
|
306
|
+
name: label,
|
|
307
|
+
assetType: guessAssetType(label, label),
|
|
308
|
+
memoryBytes: looksMb ? toBytes(num, 'mb') : toBytes(num, 'b'),
|
|
309
|
+
_source: 'overview.asset_stats',
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (Array.isArray(report['LLM'])) {
|
|
314
|
+
for (const item of report['LLM']) {
|
|
315
|
+
if (!isObj(item))
|
|
316
|
+
continue;
|
|
317
|
+
const label = String(item['label'] ?? item['key'] ?? '');
|
|
318
|
+
const num = numOf(item['value'] ?? item['data']);
|
|
319
|
+
if (!label || num == null)
|
|
320
|
+
continue;
|
|
321
|
+
memory.push({ name: label, assetType: 'LLM', memoryBytes: toBytes(num, 'b'), _source: 'overview.LLM' });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
functions.sort((a, b) => b.value - a.value);
|
|
325
|
+
memory.sort((a, b) => b.memoryBytes - a.memoryBytes);
|
|
326
|
+
const fromSection = parseHasResourceFromResourceSection(report);
|
|
327
|
+
const fromFields = parseHasResource(summary, brief);
|
|
328
|
+
return {
|
|
329
|
+
brief,
|
|
330
|
+
summary,
|
|
331
|
+
functions,
|
|
332
|
+
memory,
|
|
333
|
+
hasResource: fromSection ?? fromFields,
|
|
334
|
+
shape: briefIsArray ? 'ue-v2' : 'v1',
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/** 把 unwrap 后的报告或原始 data 统一成 OverviewView。 */
|
|
338
|
+
export function viewOverview(data) {
|
|
339
|
+
if (!data) {
|
|
340
|
+
return { brief: {}, summary: {}, functions: [], memory: [], hasResource: null, shape: 'unknown' };
|
|
341
|
+
}
|
|
342
|
+
// 数组取第一份
|
|
343
|
+
let root = data;
|
|
344
|
+
if (Array.isArray(data) && data.length)
|
|
345
|
+
root = data[0];
|
|
346
|
+
if (!isObj(root)) {
|
|
347
|
+
return { brief: {}, summary: {}, functions: [], memory: [], hasResource: null, shape: 'unknown' };
|
|
348
|
+
}
|
|
349
|
+
if (Array.isArray(root['categories']) || root['basicInfo'] != null)
|
|
350
|
+
return extractV2(root);
|
|
351
|
+
// batch map: { [dataKey]: { categories... } }
|
|
352
|
+
const values = Object.values(root);
|
|
353
|
+
if (values.length === 1 && isObj(values[0]) && (Array.isArray(values[0]['categories']) || values[0]['basicInfo'])) {
|
|
354
|
+
return extractV2(values[0]);
|
|
355
|
+
}
|
|
356
|
+
for (const k of ['reports', 'list', 'content', 'data', 'records']) {
|
|
357
|
+
const v = root[k];
|
|
358
|
+
if (Array.isArray(v) && v.length && isObj(v[0]))
|
|
359
|
+
return viewOverview(v[0]);
|
|
360
|
+
}
|
|
361
|
+
if ('brief' in root ||
|
|
362
|
+
'func' in root ||
|
|
363
|
+
'summary' in root ||
|
|
364
|
+
'asset_stats' in root ||
|
|
365
|
+
'Resource' in root ||
|
|
366
|
+
'resource' in root) {
|
|
367
|
+
return extractV1OrUe(root);
|
|
368
|
+
}
|
|
369
|
+
// 可能整包就是 v2 包在更深一层
|
|
370
|
+
if (values.length && isObj(values[0]) && Array.isArray(values[0]['categories']))
|
|
371
|
+
return extractV2(values[0]);
|
|
372
|
+
return extractV1OrUe(root);
|
|
373
|
+
}
|