tracemeld 0.1.0
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/build/analysis/bottleneck.d.ts +23 -0
- package/build/analysis/bottleneck.js +55 -0
- package/build/analysis/bottleneck.js.map +1 -0
- package/build/analysis/explain.d.ts +38 -0
- package/build/analysis/explain.js +139 -0
- package/build/analysis/explain.js.map +1 -0
- package/build/analysis/hotpaths.d.ts +19 -0
- package/build/analysis/hotpaths.js +55 -0
- package/build/analysis/hotpaths.js.map +1 -0
- package/build/analysis/hotspots.d.ts +24 -0
- package/build/analysis/hotspots.js +75 -0
- package/build/analysis/hotspots.js.map +1 -0
- package/build/analysis/query.d.ts +25 -0
- package/build/analysis/query.js +102 -0
- package/build/analysis/query.js.map +1 -0
- package/build/analysis/spinpaths.d.ts +17 -0
- package/build/analysis/spinpaths.js +48 -0
- package/build/analysis/spinpaths.js.map +1 -0
- package/build/analysis/starvations.d.ts +21 -0
- package/build/analysis/starvations.js +76 -0
- package/build/analysis/starvations.js.map +1 -0
- package/build/analysis/summary.d.ts +27 -0
- package/build/analysis/summary.js +130 -0
- package/build/analysis/summary.js.map +1 -0
- package/build/analysis/waste.d.ts +19 -0
- package/build/analysis/waste.js +33 -0
- package/build/analysis/waste.js.map +1 -0
- package/build/cli.d.ts +2 -0
- package/build/cli.js +4 -0
- package/build/cli.js.map +1 -0
- package/build/exporters/collapsed.d.ts +2 -0
- package/build/exporters/collapsed.js +34 -0
- package/build/exporters/collapsed.js.map +1 -0
- package/build/importers/chrome-trace.d.ts +2 -0
- package/build/importers/chrome-trace.js +146 -0
- package/build/importers/chrome-trace.js.map +1 -0
- package/build/importers/collapsed.d.ts +2 -0
- package/build/importers/collapsed.js +52 -0
- package/build/importers/collapsed.js.map +1 -0
- package/build/importers/detect.d.ts +2 -0
- package/build/importers/detect.js +60 -0
- package/build/importers/detect.js.map +1 -0
- package/build/importers/gecko.d.ts +2 -0
- package/build/importers/gecko.js +77 -0
- package/build/importers/gecko.js.map +1 -0
- package/build/importers/import.d.ts +11 -0
- package/build/importers/import.js +98 -0
- package/build/importers/import.js.map +1 -0
- package/build/importers/pprof.d.ts +2 -0
- package/build/importers/pprof.js +238 -0
- package/build/importers/pprof.js.map +1 -0
- package/build/importers/types.d.ts +6 -0
- package/build/importers/types.js +2 -0
- package/build/importers/types.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.js +6 -0
- package/build/index.js.map +1 -0
- package/build/instrument/mark.d.ts +11 -0
- package/build/instrument/mark.js +13 -0
- package/build/instrument/mark.js.map +1 -0
- package/build/instrument/trace.d.ts +16 -0
- package/build/instrument/trace.js +107 -0
- package/build/instrument/trace.js.map +1 -0
- package/build/model/frame-table.d.ts +10 -0
- package/build/model/frame-table.js +27 -0
- package/build/model/frame-table.js.map +1 -0
- package/build/model/profile.d.ts +20 -0
- package/build/model/profile.js +89 -0
- package/build/model/profile.js.map +1 -0
- package/build/model/state.d.ts +21 -0
- package/build/model/state.js +59 -0
- package/build/model/state.js.map +1 -0
- package/build/model/types.d.ts +73 -0
- package/build/model/types.js +10 -0
- package/build/model/types.js.map +1 -0
- package/build/patterns/blind-edit.d.ts +3 -0
- package/build/patterns/blind-edit.js +119 -0
- package/build/patterns/blind-edit.js.map +1 -0
- package/build/patterns/redundant-read.d.ts +3 -0
- package/build/patterns/redundant-read.js +72 -0
- package/build/patterns/redundant-read.js.map +1 -0
- package/build/patterns/registry.d.ts +10 -0
- package/build/patterns/registry.js +27 -0
- package/build/patterns/registry.js.map +1 -0
- package/build/patterns/retry-loop.d.ts +3 -0
- package/build/patterns/retry-loop.js +57 -0
- package/build/patterns/retry-loop.js.map +1 -0
- package/build/patterns/types.d.ts +14 -0
- package/build/patterns/types.js +2 -0
- package/build/patterns/types.js.map +1 -0
- package/build/server.d.ts +3 -0
- package/build/server.js +247 -0
- package/build/server.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { getAllSpans, extractKind, valuesToRecord } from '../analysis/query.js';
|
|
2
|
+
export function detectRedundantRead(profile) {
|
|
3
|
+
const matches = [];
|
|
4
|
+
const allSpans = getAllSpans(profile);
|
|
5
|
+
// Find turn spans using extractKind
|
|
6
|
+
const turnSpans = allSpans.filter((s) => {
|
|
7
|
+
const name = profile.frames[s.frame_index]?.name ?? '';
|
|
8
|
+
return extractKind(name) === 'turn';
|
|
9
|
+
});
|
|
10
|
+
// If no turns, treat all spans as one group
|
|
11
|
+
const groups = turnSpans.length > 0
|
|
12
|
+
? turnSpans.map((t) => getDescendantsInOrder(t, allSpans))
|
|
13
|
+
: [allSpans.sort((a, b) => a.start_time - b.start_time)];
|
|
14
|
+
for (const descendants of groups) {
|
|
15
|
+
const readsByFile = new Map();
|
|
16
|
+
for (const span of descendants) {
|
|
17
|
+
const frameName = profile.frames[span.frame_index]?.name ?? '';
|
|
18
|
+
const kind = extractKind(frameName);
|
|
19
|
+
const detail = frameName.includes(':') ? frameName.substring(frameName.indexOf(':') + 1) : '';
|
|
20
|
+
if (kind === 'file_write' && detail) {
|
|
21
|
+
readsByFile.delete(detail);
|
|
22
|
+
}
|
|
23
|
+
else if (kind === 'file_read' && detail) {
|
|
24
|
+
let reads = readsByFile.get(detail);
|
|
25
|
+
if (!reads) {
|
|
26
|
+
reads = [];
|
|
27
|
+
readsByFile.set(detail, reads);
|
|
28
|
+
}
|
|
29
|
+
reads.push(span);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const [file, reads] of readsByFile) {
|
|
33
|
+
if (reads.length >= 2) {
|
|
34
|
+
const savings = new Array(profile.value_types.length).fill(0);
|
|
35
|
+
for (let i = 1; i < reads.length; i++) {
|
|
36
|
+
for (let k = 0; k < savings.length; k++) {
|
|
37
|
+
savings[k] += reads[i].values[k] ?? 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
matches.push({
|
|
41
|
+
pattern: {
|
|
42
|
+
name: 'redundant_read',
|
|
43
|
+
description: `File '${file}' was read ${reads.length} times in one turn with no intervening write`,
|
|
44
|
+
severity: 'warning',
|
|
45
|
+
evidence: { file, read_count: reads.length },
|
|
46
|
+
},
|
|
47
|
+
span_ids: reads.map((s) => s.id),
|
|
48
|
+
counterfactual_savings: valuesToRecord(profile, savings),
|
|
49
|
+
recommendation: 'Read the file once, retain content in reasoning, plan edits before re-reading.',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return matches;
|
|
55
|
+
}
|
|
56
|
+
/** Walk the full subtree of a span, returning all descendants sorted by start_time. */
|
|
57
|
+
function getDescendantsInOrder(parent, allSpans) {
|
|
58
|
+
const result = [];
|
|
59
|
+
const stack = [...parent.children];
|
|
60
|
+
while (stack.length > 0) {
|
|
61
|
+
const id = stack.pop();
|
|
62
|
+
if (!id)
|
|
63
|
+
continue;
|
|
64
|
+
const span = allSpans.find((s) => s.id === id);
|
|
65
|
+
if (!span)
|
|
66
|
+
continue;
|
|
67
|
+
result.push(span);
|
|
68
|
+
stack.push(...span.children);
|
|
69
|
+
}
|
|
70
|
+
return result.sort((a, b) => a.start_time - b.start_time);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=redundant-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redundant-read.js","sourceRoot":"","sources":["../../src/patterns/redundant-read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Profile } from '../model/types.js';
|
|
2
|
+
import type { PatternDetector, PatternMatch } from './types.js';
|
|
3
|
+
export declare class PatternRegistry {
|
|
4
|
+
private detectors;
|
|
5
|
+
private cache;
|
|
6
|
+
register(detector: PatternDetector): void;
|
|
7
|
+
detect(profile: Profile): PatternMatch[];
|
|
8
|
+
getMatchesForSpan(profile: Profile, spanId: string): PatternMatch[];
|
|
9
|
+
invalidate(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class PatternRegistry {
|
|
2
|
+
detectors = [];
|
|
3
|
+
cache = null;
|
|
4
|
+
register(detector) {
|
|
5
|
+
this.detectors.push(detector);
|
|
6
|
+
this.cache = null;
|
|
7
|
+
}
|
|
8
|
+
detect(profile) {
|
|
9
|
+
if (this.cache && this.cache.profileId === profile.id) {
|
|
10
|
+
return this.cache.matches;
|
|
11
|
+
}
|
|
12
|
+
const matches = [];
|
|
13
|
+
for (const detector of this.detectors) {
|
|
14
|
+
matches.push(...detector(profile));
|
|
15
|
+
}
|
|
16
|
+
this.cache = { profileId: profile.id, matches };
|
|
17
|
+
return matches;
|
|
18
|
+
}
|
|
19
|
+
getMatchesForSpan(profile, spanId) {
|
|
20
|
+
const all = this.detect(profile);
|
|
21
|
+
return all.filter((m) => m.span_ids.includes(spanId));
|
|
22
|
+
}
|
|
23
|
+
invalidate() {
|
|
24
|
+
this.cache = null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/patterns/registry.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,eAAe;IAClB,SAAS,GAAsB,EAAE,CAAC;IAClC,KAAK,GAA0D,IAAI,CAAC;IAE5E,QAAQ,CAAC,QAAyB;QAChC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,OAAgB;QACrB,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,EAAE,CAAC;YACtD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QAC5B,CAAC;QAED,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC;QAChD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,iBAAiB,CAAC,OAAgB,EAAE,MAAc;QAChD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getAllSpans, valuesToRecord } from '../analysis/query.js';
|
|
2
|
+
export function detectRetryLoop(profile) {
|
|
3
|
+
const matches = [];
|
|
4
|
+
const allSpans = getAllSpans(profile);
|
|
5
|
+
// Group spans by parent_id to find siblings
|
|
6
|
+
const siblingGroups = new Map();
|
|
7
|
+
for (const span of allSpans) {
|
|
8
|
+
const parentKey = span.parent_id ?? '__root__';
|
|
9
|
+
let group = siblingGroups.get(parentKey);
|
|
10
|
+
if (!group) {
|
|
11
|
+
group = [];
|
|
12
|
+
siblingGroups.set(parentKey, group);
|
|
13
|
+
}
|
|
14
|
+
group.push(span);
|
|
15
|
+
}
|
|
16
|
+
for (const siblings of siblingGroups.values()) {
|
|
17
|
+
siblings.sort((a, b) => a.start_time - b.start_time);
|
|
18
|
+
let i = 0;
|
|
19
|
+
while (i < siblings.length) {
|
|
20
|
+
const run = [siblings[i]];
|
|
21
|
+
while (i + 1 < siblings.length &&
|
|
22
|
+
siblings[i + 1].frame_index === run[0].frame_index) {
|
|
23
|
+
i++;
|
|
24
|
+
run.push(siblings[i]);
|
|
25
|
+
}
|
|
26
|
+
// A retry loop: 2+ consecutive same-frame spans where at least one (except possibly last) has error
|
|
27
|
+
if (run.length >= 2) {
|
|
28
|
+
const hasError = run.slice(0, -1).some((s) => s.error);
|
|
29
|
+
if (hasError) {
|
|
30
|
+
const savings = new Array(profile.value_types.length).fill(0);
|
|
31
|
+
for (let j = 0; j < run.length - 1; j++) {
|
|
32
|
+
for (let k = 0; k < savings.length; k++) {
|
|
33
|
+
savings[k] += run[j].values[k] ?? 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
matches.push({
|
|
37
|
+
pattern: {
|
|
38
|
+
name: 'retry_loop',
|
|
39
|
+
description: `${run.length} consecutive attempts of the same operation with intervening errors`,
|
|
40
|
+
severity: run.length >= 3 ? 'warning' : 'info',
|
|
41
|
+
evidence: {
|
|
42
|
+
attempt_count: run.length,
|
|
43
|
+
errors: run.filter((s) => s.error).map((s) => s.error),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
span_ids: run.map((s) => s.id),
|
|
47
|
+
counterfactual_savings: valuesToRecord(profile, savings),
|
|
48
|
+
recommendation: 'Read the error carefully before retrying. Consider a different approach after the first failure.',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return matches;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=retry-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-loop.js","sourceRoot":"","sources":["../../src/patterns/retry-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Profile, DetectedPattern } from '../model/types.js';
|
|
2
|
+
/** A match produced by a pattern detector. */
|
|
3
|
+
export interface PatternMatch {
|
|
4
|
+
/** The detected pattern (name, description, severity, evidence). */
|
|
5
|
+
pattern: DetectedPattern;
|
|
6
|
+
/** Span IDs involved in this match. */
|
|
7
|
+
span_ids: string[];
|
|
8
|
+
/** Estimated savings if this waste were eliminated. Keyed by value_type.key. */
|
|
9
|
+
counterfactual_savings: Record<string, number>;
|
|
10
|
+
/** Concrete recommendation for the LLM. */
|
|
11
|
+
recommendation: string;
|
|
12
|
+
}
|
|
13
|
+
/** A pattern detector function. Pure: profile in, matches out. */
|
|
14
|
+
export type PatternDetector = (profile: Profile) => PatternMatch[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/patterns/types.ts"],"names":[],"mappings":""}
|
package/build/server.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { ProfilerState } from './model/state.js';
|
|
5
|
+
import { handleTrace } from './instrument/trace.js';
|
|
6
|
+
import { handleMark } from './instrument/mark.js';
|
|
7
|
+
import { profileSummary } from './analysis/summary.js';
|
|
8
|
+
import { findHotspots } from './analysis/hotspots.js';
|
|
9
|
+
import { explainSpan } from './analysis/explain.js';
|
|
10
|
+
import { findWaste } from './analysis/waste.js';
|
|
11
|
+
import { importProfile } from './importers/import.js';
|
|
12
|
+
import { exportCollapsed } from './exporters/collapsed.js';
|
|
13
|
+
import { findHotpaths } from './analysis/hotpaths.js';
|
|
14
|
+
import { findBottlenecks } from './analysis/bottleneck.js';
|
|
15
|
+
import { findSpinpaths } from './analysis/spinpaths.js';
|
|
16
|
+
import { findStarvations } from './analysis/starvations.js';
|
|
17
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
18
|
+
export function createServer() {
|
|
19
|
+
const server = new McpServer({
|
|
20
|
+
name: 'tracemeld',
|
|
21
|
+
version: '0.1.0',
|
|
22
|
+
});
|
|
23
|
+
const state = new ProfilerState();
|
|
24
|
+
server.registerTool('trace', {
|
|
25
|
+
description: "Mark the start or end of a unit of work. Use this to instrument your own operations while you work: thinking, tool calls, file reads, bash commands, test runs. Call with action 'begin' before starting, 'end' when done. Cost data (tokens, time, bytes) goes on the 'end' call. Nesting is automatic.",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
action: z.enum(['begin', 'end']),
|
|
28
|
+
kind: z.string(),
|
|
29
|
+
name: z.string().optional(),
|
|
30
|
+
cost: z.record(z.string(), z.number()).optional(),
|
|
31
|
+
error: z.string().optional(),
|
|
32
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
33
|
+
},
|
|
34
|
+
}, (args) => {
|
|
35
|
+
const result = handleTrace(state, args);
|
|
36
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
37
|
+
});
|
|
38
|
+
server.registerTool('mark', {
|
|
39
|
+
description: "Record a notable instant: a test failure, a decision point, context window pressure, an unexpected result. Not a duration \u2014 a moment.",
|
|
40
|
+
inputSchema: {
|
|
41
|
+
what: z.string(),
|
|
42
|
+
severity: z.enum(['info', 'warning', 'error']).optional(),
|
|
43
|
+
data: z.record(z.string(), z.unknown()).optional(),
|
|
44
|
+
},
|
|
45
|
+
}, (args) => {
|
|
46
|
+
const result = handleMark(state, args);
|
|
47
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
48
|
+
});
|
|
49
|
+
server.registerTool('profile_summary', {
|
|
50
|
+
description: 'Get headline performance numbers for a session: total time, tokens, cost, errors. Group by turn, operation kind, or execution lane to see where effort concentrated. Start here when you want to understand how a session went.',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
group_by: z.enum(['kind', 'turn', 'lane']).optional(),
|
|
53
|
+
time_range: z
|
|
54
|
+
.object({
|
|
55
|
+
start_ms: z.number(),
|
|
56
|
+
end_ms: z.number(),
|
|
57
|
+
})
|
|
58
|
+
.optional(),
|
|
59
|
+
},
|
|
60
|
+
}, (args) => {
|
|
61
|
+
const result = profileSummary(state.builder.profile, args);
|
|
62
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
63
|
+
});
|
|
64
|
+
server.registerTool('hotspots', {
|
|
65
|
+
description: 'Find the most expensive operations by any dimension: wall time, tokens consumed, tokens generated, dollar cost, or error count. Returns a ranked list with ancestry chains. Use after profile_summary identifies a concentration of cost.',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
dimension: z.string(),
|
|
68
|
+
top_n: z.number().optional(),
|
|
69
|
+
min_value: z.number().optional(),
|
|
70
|
+
},
|
|
71
|
+
}, (args) => {
|
|
72
|
+
const result = findHotspots(state.builder.profile, args, state.registry);
|
|
73
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
74
|
+
});
|
|
75
|
+
server.registerTool('explain_span', {
|
|
76
|
+
description: 'Deep-dive into one expensive span. Shows its child breakdown, the causal chain of what happened, and any detected anti-patterns. Use when hotspots identified a specific span to investigate.',
|
|
77
|
+
inputSchema: {
|
|
78
|
+
span_id: z.string(),
|
|
79
|
+
},
|
|
80
|
+
}, (args) => {
|
|
81
|
+
const result = explainSpan(state.builder.profile, args, state.registry);
|
|
82
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
83
|
+
});
|
|
84
|
+
server.registerTool('find_waste', {
|
|
85
|
+
description: 'Identify work that didn\'t contribute to the final result: retries, unused reads, blind edits. Each waste item includes counterfactual savings and a concrete recommendation.',
|
|
86
|
+
inputSchema: {
|
|
87
|
+
time_range: z
|
|
88
|
+
.object({
|
|
89
|
+
start_ms: z.number(),
|
|
90
|
+
end_ms: z.number(),
|
|
91
|
+
})
|
|
92
|
+
.optional(),
|
|
93
|
+
},
|
|
94
|
+
}, (args) => {
|
|
95
|
+
const result = findWaste(state.builder.profile, state.registry, args);
|
|
96
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
97
|
+
});
|
|
98
|
+
server.registerTool('import_profile', {
|
|
99
|
+
description: "Load profiling data from a file path or inline string. Auto-detects format (collapsed stacks, Chrome trace) or accepts a hint. Use when you want to analyze an existing profile.",
|
|
100
|
+
inputSchema: {
|
|
101
|
+
source: z.string().describe('File path or inline profile data string'),
|
|
102
|
+
format: z.enum(['auto', 'collapsed', 'chrome_trace', 'gecko', 'pprof', 'speedscope']).optional(),
|
|
103
|
+
lane_name: z.string().optional(),
|
|
104
|
+
},
|
|
105
|
+
}, (args) => {
|
|
106
|
+
let content;
|
|
107
|
+
const format = args.format ?? 'auto';
|
|
108
|
+
if (!args.source.includes('\n') && existsSync(args.source)) {
|
|
109
|
+
// Binary formats (pprof) must be read as latin1 to preserve bytes
|
|
110
|
+
const isBinary = format === 'pprof' || args.source.endsWith('.pb.gz') || args.source.endsWith('.prof');
|
|
111
|
+
content = readFileSync(args.source, isBinary ? 'latin1' : 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
content = args.source;
|
|
115
|
+
}
|
|
116
|
+
const result = importProfile(content, args.lane_name ?? 'imported', format, state.builder);
|
|
117
|
+
state.invalidatePatternCache();
|
|
118
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
119
|
+
});
|
|
120
|
+
server.registerTool('export_profile', {
|
|
121
|
+
description: "Export the current profile to a standard format for visualization. Currently supports 'collapsed' (for flamegraph tools). Returns the data as a string or writes to file.",
|
|
122
|
+
inputSchema: {
|
|
123
|
+
format: z.enum(['collapsed']).describe('Export format'),
|
|
124
|
+
dimension: z.string().optional().describe('Value type key to export (default: first value type)'),
|
|
125
|
+
output_path: z.string().optional().describe('File path to write. If omitted, returns data inline.'),
|
|
126
|
+
},
|
|
127
|
+
}, (args) => {
|
|
128
|
+
const data = exportCollapsed(state.builder.profile, args.dimension ?? 0);
|
|
129
|
+
if (args.output_path) {
|
|
130
|
+
writeFileSync(args.output_path, data, 'utf-8');
|
|
131
|
+
return {
|
|
132
|
+
content: [{
|
|
133
|
+
type: 'text',
|
|
134
|
+
text: JSON.stringify({
|
|
135
|
+
format: args.format,
|
|
136
|
+
file_path: args.output_path,
|
|
137
|
+
size_bytes: Buffer.byteLength(data, 'utf-8'),
|
|
138
|
+
notes: [],
|
|
139
|
+
}),
|
|
140
|
+
}],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
content: [{
|
|
145
|
+
type: 'text',
|
|
146
|
+
text: JSON.stringify({
|
|
147
|
+
format: args.format,
|
|
148
|
+
data,
|
|
149
|
+
size_bytes: Buffer.byteLength(data, 'utf-8'),
|
|
150
|
+
notes: [],
|
|
151
|
+
}),
|
|
152
|
+
}],
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
server.registerTool('hotpaths', {
|
|
156
|
+
description: "Find the critical call paths that account for the most cost. Unlike hotspots (flat ranking), this shows complete root-to-leaf paths. Use to understand which call chains dominate execution.",
|
|
157
|
+
inputSchema: { dimension: z.string(), top_n: z.number().optional() },
|
|
158
|
+
}, (args) => {
|
|
159
|
+
const result = findHotpaths(state.builder.profile, args);
|
|
160
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
161
|
+
});
|
|
162
|
+
server.registerTool('bottleneck', {
|
|
163
|
+
description: "Find the single operations where optimization would have the most impact. Combines self-cost with path criticality — 'if you could speed up one thing, what would move the needle?'",
|
|
164
|
+
inputSchema: { dimension: z.string(), top_n: z.number().optional() },
|
|
165
|
+
}, (args) => {
|
|
166
|
+
const result = findBottlenecks(state.builder.profile, args);
|
|
167
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
168
|
+
});
|
|
169
|
+
server.registerTool('spinpaths', {
|
|
170
|
+
description: "Detect operations with high wall time but low useful output — busy-waiting, spinning, or inefficient processing. Flags spans that spent significant time without producing tokens, bytes, or other measurable work.",
|
|
171
|
+
inputSchema: { min_wall_ms: z.number().optional() },
|
|
172
|
+
}, (args) => {
|
|
173
|
+
const result = findSpinpaths(state.builder.profile, args);
|
|
174
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
175
|
+
});
|
|
176
|
+
server.registerTool('starvations', {
|
|
177
|
+
description: "Detect threads/lanes that are idle while others are active — indicates lock contention, unbalanced work, or serialization. Most useful with multi-threaded imported profiles (Gecko, Chrome trace).",
|
|
178
|
+
inputSchema: { min_idle_pct: z.number().optional() },
|
|
179
|
+
}, (args) => {
|
|
180
|
+
const result = findStarvations(state.builder.profile, args);
|
|
181
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
182
|
+
});
|
|
183
|
+
server.registerPrompt('performance_review', {
|
|
184
|
+
title: 'Performance Review',
|
|
185
|
+
description: 'Step-by-step analysis of the current profile. Finds bottlenecks, traces call paths, identifies waste, and produces actionable recommendations with source locations.',
|
|
186
|
+
}, () => ({
|
|
187
|
+
messages: [{
|
|
188
|
+
role: 'user',
|
|
189
|
+
content: {
|
|
190
|
+
type: 'text',
|
|
191
|
+
text: `You have a performance profile loaded in tracemeld. Analyze it step by step:
|
|
192
|
+
|
|
193
|
+
1. Call profile_summary with group_by="kind" to get headline numbers.
|
|
194
|
+
2. Look at which group has the highest pct_of_total on any dimension.
|
|
195
|
+
3. Call bottleneck on that dimension with top_n=5 to find the biggest optimization targets.
|
|
196
|
+
4. For each bottleneck that has a source field, read the source file at that line to understand the implementation. Use LSP hover and findReferences to understand the function's role.
|
|
197
|
+
5. Call hotpaths on the same dimension to see complete call chains.
|
|
198
|
+
6. Call find_waste to identify work that didn't contribute to the result.
|
|
199
|
+
7. Synthesize your findings into:
|
|
200
|
+
- What's the #1 bottleneck and what does the source code reveal about why?
|
|
201
|
+
- What work was wasted (with specific anti-patterns)?
|
|
202
|
+
- Concrete recommendations with code-level specificity (cite file:line locations).`,
|
|
203
|
+
},
|
|
204
|
+
}],
|
|
205
|
+
}));
|
|
206
|
+
server.registerPrompt('optimize_for', {
|
|
207
|
+
title: 'Optimize For Dimension',
|
|
208
|
+
description: 'Targeted optimization analysis for a specific cost dimension (wall_ms, input_tokens, etc.)',
|
|
209
|
+
argsSchema: {
|
|
210
|
+
dimension: z.string().describe('The cost dimension to optimize: wall_ms, input_tokens, output_tokens, cost_usd, etc.'),
|
|
211
|
+
},
|
|
212
|
+
}, ({ dimension }) => ({
|
|
213
|
+
messages: [{
|
|
214
|
+
role: 'user',
|
|
215
|
+
content: {
|
|
216
|
+
type: 'text',
|
|
217
|
+
text: `Optimize for: ${dimension}
|
|
218
|
+
|
|
219
|
+
1. Call bottleneck with dimension="${dimension}" and top_n=5.
|
|
220
|
+
2. For each bottleneck with a source field, read the code at that location. Use LSP to understand what the function does and who calls it.
|
|
221
|
+
3. Call hotpaths with dimension="${dimension}" to see the full call chains.
|
|
222
|
+
4. Call find_waste to identify redundant work.
|
|
223
|
+
5. Produce a ranked list of optimizations, ordered by expected savings on ${dimension}. For each recommendation, cite the specific file:line and explain what to change.`,
|
|
224
|
+
},
|
|
225
|
+
}],
|
|
226
|
+
}));
|
|
227
|
+
server.registerResource('profile-summary', 'profile://summary', {
|
|
228
|
+
title: 'Current Profile Summary',
|
|
229
|
+
description: 'Headline numbers from the active tracemeld profile — span count, error count, cost totals by kind.',
|
|
230
|
+
mimeType: 'application/json',
|
|
231
|
+
}, () => {
|
|
232
|
+
const summary = profileSummary(state.builder.profile, { group_by: 'kind' });
|
|
233
|
+
return {
|
|
234
|
+
contents: [{
|
|
235
|
+
uri: 'profile://summary',
|
|
236
|
+
text: JSON.stringify(summary, null, 2),
|
|
237
|
+
}],
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
return server;
|
|
241
|
+
}
|
|
242
|
+
export async function startServer() {
|
|
243
|
+
const server = createServer();
|
|
244
|
+
const transport = new StdioServerTransport();
|
|
245
|
+
await server.connect(transport);
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tracemeld",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "LLM-native MCP server for performance profiling and analysis",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./build/index.js",
|
|
7
|
+
"types": "./build/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"tracemeld": "./build/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"lint": "eslint src/",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
"inspect": "npm run build && npx @modelcontextprotocol/inspector node ./build/cli.js",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"build/**/*.js",
|
|
22
|
+
"build/**/*.d.ts",
|
|
23
|
+
"build/**/*.js.map",
|
|
24
|
+
"!build/**/*.test.*",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
33
|
+
"pako": "^2.1.0",
|
|
34
|
+
"zod": "^4.3.6"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@modelcontextprotocol/inspector": "^0.21.1",
|
|
38
|
+
"@types/node": "^25.5.0",
|
|
39
|
+
"@types/pako": "^2.0.4",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
41
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
42
|
+
"eslint": "^10.0.3",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"typescript-eslint": "^8.57.1",
|
|
45
|
+
"vitest": "^4.1.0"
|
|
46
|
+
}
|
|
47
|
+
}
|