perf-skill 0.2.1 → 0.4.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.
Files changed (51) hide show
  1. package/.claude-plugin/README.md +48 -0
  2. package/.claude-plugin/marketplace.json +27 -0
  3. package/.claude-plugin/plugin.json +21 -0
  4. package/CLAUDE.md +166 -0
  5. package/README.md +128 -109
  6. package/dist/cli/init.d.ts +19 -3
  7. package/dist/cli/init.d.ts.map +1 -1
  8. package/dist/cli/init.js +108 -11
  9. package/dist/cli/init.js.map +1 -1
  10. package/dist/cli/main.js +72 -49
  11. package/dist/cli/main.js.map +1 -1
  12. package/dist/cli/platforms.d.ts +28 -0
  13. package/dist/cli/platforms.d.ts.map +1 -0
  14. package/dist/cli/platforms.js +238 -0
  15. package/dist/cli/platforms.js.map +1 -0
  16. package/dist/cli/template.d.ts +16 -0
  17. package/dist/cli/template.d.ts.map +1 -0
  18. package/dist/cli/template.js +157 -0
  19. package/dist/cli/template.js.map +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +71 -36
  22. package/dist/index.js.map +1 -1
  23. package/dist/llm/client.d.ts +6 -0
  24. package/dist/llm/client.d.ts.map +1 -1
  25. package/dist/llm/client.js +11 -2
  26. package/dist/llm/client.js.map +1 -1
  27. package/dist/llm/index.d.ts +1 -1
  28. package/dist/llm/index.d.ts.map +1 -1
  29. package/dist/llm/index.js +1 -1
  30. package/dist/llm/index.js.map +1 -1
  31. package/dist/skill/handler.d.ts +7 -0
  32. package/dist/skill/handler.d.ts.map +1 -1
  33. package/dist/skill/handler.js +24 -1
  34. package/dist/skill/handler.js.map +1 -1
  35. package/dist/skill/manifest.d.ts +4 -0
  36. package/dist/skill/manifest.d.ts.map +1 -1
  37. package/dist/skill/manifest.js +60 -39
  38. package/dist/skill/manifest.js.map +1 -1
  39. package/dist/types.d.ts +2 -0
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +13 -10
  42. package/skills/perf-skill/SKILL.md +194 -0
  43. package/SKILL.md +0 -238
  44. package/dist/server/http.d.ts +0 -27
  45. package/dist/server/http.d.ts.map +0 -1
  46. package/dist/server/http.js +0 -285
  47. package/dist/server/http.js.map +0 -1
  48. package/dist/server/utils.d.ts +0 -15
  49. package/dist/server/utils.d.ts.map +0 -1
  50. package/dist/server/utils.js +0 -71
  51. package/dist/server/utils.js.map +0 -1
@@ -0,0 +1,194 @@
1
+ ---
2
+ name: perf-skill
3
+ description: Convert pprof CPU and heap profiles to structured Markdown and JSON evidence. Use when the user has a .pb.gz profile file and wants to understand performance bottlenecks or compare profiles.
4
+ argument-hint: "[profile.pb.gz] [options]"
5
+ allowed-tools: Bash(node *), Bash(npx *), Read, Glob
6
+ ---
7
+
8
+ # perf-skill: Performance Profile Evidence Extractor
9
+
10
+ Convert pprof profiles (.pb.gz) to structured Markdown and JSON for performance analysis. This tool produces **deterministic, evidence-based output** that you (the agent) can use to generate optimization recommendations.
11
+
12
+ ## Design Philosophy
13
+
14
+ - **Deterministic by default**: No external API calls or LLM dependencies
15
+ - **Evidence-first**: Produces structured hotspots, call paths, and metrics
16
+ - **Agent-friendly**: You (Claude/Cursor/any coding agent) provide the analysis and recommendations based on the evidence
17
+
18
+ ## Quick Start
19
+
20
+ ### Analyze a Single Profile
21
+
22
+ ```bash
23
+ # Convert profile to structured markdown and JSON (default, no LLM required)
24
+ npx perf-skill analyze $ARGUMENTS -o analysis.md -j results.json
25
+
26
+ # Or use the convert command (explicitly no LLM)
27
+ npx perf-skill convert $ARGUMENTS -o report.md
28
+ ```
29
+
30
+ ### Compare Two Profiles (Diff)
31
+
32
+ ```bash
33
+ # Compare base vs current profile
34
+ npx perf-skill diff base.pb.gz current.pb.gz -o diff.md -j diff.json
35
+ ```
36
+
37
+ ### Profile a Node.js Application
38
+
39
+ ```bash
40
+ # Profile and convert in one step
41
+ npx perf-skill run slow.mjs --duration 10s -o cpu.md -j cpu.json
42
+
43
+ # With heap profiling
44
+ npx perf-skill run slow.mjs --heap --output cpu.md --heap-output heap.md
45
+ ```
46
+
47
+ ## Workflow for Performance Analysis
48
+
49
+ 1. **Run perf-skill** to generate evidence (markdown + JSON)
50
+ 2. **Read the output** to understand hotspots and call paths
51
+ 3. **Generate recommendations** based on the evidence (this is YOUR job as the agent)
52
+ 4. **Implement changes** and re-run profiling to verify improvements
53
+
54
+ ## When to Use This Skill
55
+
56
+ Use `perf-skill` when:
57
+ - User provides a `.pb.gz` pprof profile file
58
+ - User asks "why is my app slow?" with a profile attached
59
+ - User wants to compare performance before/after a change
60
+ - User needs help interpreting profile data
61
+ - User asks about CPU or memory hotspots
62
+
63
+ ## Available Commands
64
+
65
+ ### `analyze` (default)
66
+
67
+ Convert a profile to structured Markdown. Default mode is `convert-only` (no external dependencies).
68
+
69
+ ```bash
70
+ perf-skill analyze profile.pb.gz [options]
71
+ ```
72
+
73
+ **Key Options:**
74
+ - `-f, --format <format>`: Output format (`summary`, `detailed`, `adaptive`)
75
+ - `-t, --type <type>`: Profile type (`cpu`, `heap`, `auto`)
76
+ - `-o, --output <file>`: Save markdown to file
77
+ - `-j, --json <file>`: Save JSON results to file (for programmatic access)
78
+ - `--max-hotspots <n>`: Limit hotspots shown (default: 10)
79
+ - `--service <name>`: Service name for context
80
+ - `--scenario <desc>`: Scenario description
81
+
82
+ ### `diff`
83
+
84
+ Compare two profiles to find performance regressions.
85
+
86
+ ```bash
87
+ perf-skill diff base.pb.gz current.pb.gz [options]
88
+ ```
89
+
90
+ **Key Options:**
91
+ - `-f, --format <format>`: `diff-summary`, `diff-detailed`, `diff-adaptive`
92
+ - `-n, --normalize <mode>`: `none`, `scale-to-base-total`, `per-second`
93
+ - `-o, --output <file>`: Save markdown to file
94
+ - `-j, --json <file>`: Save JSON results to file
95
+ - `--max-regressions <n>`: Limit regressions shown (default: 10)
96
+ - `--max-improvements <n>`: Limit improvements shown (default: 5)
97
+
98
+ ### `convert`
99
+
100
+ Explicitly convert profile to markdown (same as analyze with default settings).
101
+
102
+ ```bash
103
+ perf-skill convert profile.pb.gz -o report.md
104
+ ```
105
+
106
+ ### `run`
107
+
108
+ Profile a Node.js entry file and convert the results.
109
+
110
+ ```bash
111
+ perf-skill run slow.mjs --duration 10s -o cpu.md
112
+ ```
113
+
114
+ ### `profile`
115
+
116
+ Only generate profile files without conversion.
117
+
118
+ ```bash
119
+ perf-skill profile slow.mjs --duration 10s -o cpu.pb.gz
120
+ ```
121
+
122
+ ## Understanding the Output
123
+
124
+ ### Hotspots (JSON structure)
125
+
126
+ ```json
127
+ {
128
+ "hotspots": [
129
+ {
130
+ "rank": 1,
131
+ "function": "processRequest",
132
+ "selfPct": 23.4,
133
+ "cumPct": 67.8,
134
+ "location": "src/handler.ts:142",
135
+ "callPath": ["main", "handleHttp", "processRequest"]
136
+ }
137
+ ]
138
+ }
139
+ ```
140
+
141
+ - **selfPct**: Time/memory spent in this function only (high = expensive work)
142
+ - **cumPct**: Time/memory including callees (high = hot path entry point)
143
+ - **callPath**: Call stack from root to this function
144
+
145
+ ### Diff Analysis (JSON structure)
146
+
147
+ ```json
148
+ {
149
+ "regressions": [...],
150
+ "improvements": [...],
151
+ "summary": ["Overall performance regressed by ~5%", "..."]
152
+ }
153
+ ```
154
+
155
+ ## Tips for Analysis
156
+
157
+ 1. **High self%** = function is doing expensive work directly → optimize the function body
158
+ 2. **High cum%** = function is on a hot path → may need to call faster alternatives or cache
159
+ 3. **Native functions** (like `JSON.parse`) at top → consider streaming/binary alternatives
160
+ 4. **Compare profiles** to find the cause of regressions after code changes
161
+ 5. **Low sample count** → run profiler longer for statistical significance
162
+
163
+ ## Example Agent Workflow
164
+
165
+ ```markdown
166
+ User: "My API is slow, here's the profile: cpu.pb.gz"
167
+
168
+ Agent:
169
+ 1. Run: `npx perf-skill analyze cpu.pb.gz -o analysis.md -j results.json`
170
+ 2. Read the output files
171
+ 3. Analyze hotspots and generate recommendations:
172
+ - "JSON.parse at 23% - consider streaming JSON parser"
173
+ - "processRequest has high cumulative time - trace callees"
174
+ 4. Implement changes
175
+ 5. Re-profile and use `perf-skill diff` to verify improvement
176
+ ```
177
+
178
+ ## Requirements
179
+
180
+ - Node.js >= 20
181
+
182
+ ## Troubleshooting
183
+
184
+ ### "No symbols found"
185
+ The profile may be from a production build without debug info. Analysis still works but function names may be mangled.
186
+
187
+ ### "Native code dominates"
188
+ If native functions (like `JSON.parse`) are top hotspots, consider:
189
+ - Using streaming parsers for large JSON
190
+ - Caching parsed results
191
+ - Using binary formats like Protocol Buffers
192
+
193
+ ### "Low sample count"
194
+ Run the profiler longer to get more samples for statistical significance.
package/SKILL.md DELETED
@@ -1,238 +0,0 @@
1
- ---
2
- name: perf-skill
3
- description: Analyze pprof CPU and heap profiles with AI-powered recommendations, or profile a Node.js entry file and generate a full report. Use when the user has a .pb.gz profile file or wants to profile a Node.js script and get optimization suggestions.
4
- argument-hint: [profile.pb.gz|entry.js] [options]
5
- allowed-tools: Bash(node *), Bash(npx *), Read, Glob
6
- ---
7
-
8
- # perf-skill: Performance Profile Analysis Skill
9
-
10
- Analyze pprof profiles (.pb.gz) to identify performance bottlenecks and generate actionable optimization recommendations.
11
-
12
- ## Quick Start
13
-
14
- ### Analyze a Single Profile
15
-
16
- ```bash
17
- # Quick conversion to markdown (no LLM)
18
- npx perf-skill convert $ARGUMENTS
19
-
20
- # Full analysis with AI recommendations
21
- npx perf-skill analyze $ARGUMENTS --mode analyze
22
-
23
- # Output to file
24
- npx perf-skill analyze $ARGUMENTS -o analysis.md -j results.json
25
- ```
26
-
27
- ### Profile a Node Entry and Analyze (One Command)
28
-
29
- ```bash
30
- # Default CPU profiling (10s) + analysis
31
- npx perf-skill run slow.mjs
32
-
33
- # Customize duration and output
34
- npx perf-skill run slow.mjs --duration 10s -o analysis.md
35
-
36
- # CPU + Heap profiling (separate reports)
37
- npx perf-skill run slow.mjs --heap --output cpu.md --heap-output heap.md
38
- ```
39
-
40
- ### Compare Two Profiles (Diff)
41
-
42
- ```bash
43
- # Compare base vs current profile
44
- npx perf-skill diff base.pb.gz current.pb.gz
45
-
46
- # With specific format
47
- npx perf-skill diff base.pb.gz current.pb.gz --format diff-detailed
48
- ```
49
-
50
- ## When to Use This Skill
51
-
52
- Use `perf-skill` when:
53
- - User provides a `.pb.gz` pprof profile file
54
- - User provides a Node.js entry file (`.js/.mjs/.cjs`) and wants an end-to-end performance report
55
- - User asks "why is my app slow?" with a profile attached
56
- - User wants to compare performance before/after a change
57
- - User needs help interpreting profile data
58
- - User asks about CPU or memory hotspots
59
-
60
- ## Routing
61
-
62
- - If the argument ends with `.pb`, `.pb.gz`, or `.pprof`, run `analyze` or `diff` directly.
63
- - If the argument ends with `.js`, `.mjs`, or `.cjs`, run `perf-skill run <entry>` to generate a CPU profile and analyze it.
64
- - If the user asks for both CPU and heap (including misspellings like "heep" or terms like "memory"/"heap"), add `--heap` and save separate reports (`--output` + `--heap-output`).
65
-
66
- ## Available Commands
67
-
68
- ### `analyze` (default)
69
-
70
- Analyze a single profile with optional AI recommendations.
71
-
72
- ```bash
73
- perf-skill analyze profile.pb.gz [options]
74
- ```
75
-
76
- **Options:**
77
- - `-f, --format <format>`: Output format (`summary`, `detailed`, `adaptive`)
78
- - `-t, --type <type>`: Profile type (`cpu`, `heap`, `auto`)
79
- - `-o, --output <file>`: Save markdown to file
80
- - `-j, --json <file>`: Save JSON results to file
81
- - `-m, --mode <mode>`: `convert-only` (no LLM) or `analyze` (with LLM)
82
- - `-s, --source-dir <path>`: Include source code context
83
- - `--max-hotspots <n>`: Limit hotspots shown (default: 10)
84
- - `--service <name>`: Service name for context
85
- - `--scenario <desc>`: Scenario description
86
-
87
- ### `diff`
88
-
89
- Compare two profiles to find performance regressions.
90
-
91
- ```bash
92
- perf-skill diff base.pb.gz current.pb.gz [options]
93
- ```
94
-
95
- **Options:**
96
- - `-f, --format <format>`: `diff-summary`, `diff-detailed`, `diff-adaptive`
97
- - `-n, --normalize <mode>`: `none`, `scale-to-base-total`, `per-second`
98
- - `--max-regressions <n>`: Limit regressions shown (default: 10)
99
- - `--max-improvements <n>`: Limit improvements shown (default: 5)
100
-
101
- ### `convert`
102
-
103
- Convert profile to markdown without AI analysis (faster).
104
-
105
- ```bash
106
- perf-skill convert profile.pb.gz -o report.md
107
- ```
108
-
109
- ### `run`
110
-
111
- Profile a Node entry file (CPU) and analyze the resulting profile.
112
-
113
- ```bash
114
- perf-skill run entry.js [entryArgs...]
115
- ```
116
-
117
- **Options:**
118
- - `-d, --duration <duration>`: Profiling duration (default: `10s`)
119
- - `--profile-out <file>`: Profile output file (default: `cpu.pb.gz`)
120
- - `--heap`: Also capture heap profile
121
- - `--heap-profile-out <file>`: Heap profile output file (default: `heap.pb.gz`)
122
- - `--heap-output <file>`: Heap markdown output file (default: derived from CPU output or `heap.md`)
123
- - `--heap-json <file>`: Heap JSON output file (optional)
124
- - `--heap-interval-bytes <n>`: Heap sampling interval (bytes, default: `524288`)
125
- - `--heap-stack-depth <n>`: Heap sampling stack depth (default: `64`)
126
- - All `analyze` options (`--format`, `--mode`, `--output`, etc.)
127
-
128
- When `--heap` is enabled and `--output` is omitted, the CLI writes `cpu.md` and `heap.md` instead of printing to stdout.
129
-
130
- ### `profile`
131
-
132
- Generate a CPU profile for a Node entry file without analysis.
133
-
134
- ```bash
135
- perf-skill profile entry.js [entryArgs...]
136
- ```
137
-
138
- **Options:**
139
- - `-d, --duration <duration>`: Profiling duration (default: `10s`)
140
- - `-o, --output <file>`: Profile output file (default: `cpu.pb.gz`)
141
- - `--heap`: Also capture heap profile
142
- - `--heap-profile-out <file>`: Heap profile output file (default: `heap.pb.gz`)
143
- - `--heap-interval-bytes <n>`: Heap sampling interval (bytes, default: `524288`)
144
- - `--heap-stack-depth <n>`: Heap sampling stack depth (default: `64`)
145
-
146
- ## Programmatic Usage
147
-
148
- ```typescript
149
- import { analyze, diff } from 'perf-skill';
150
-
151
- // Analyze with AI
152
- const result = await analyze('cpu.pb.gz', {
153
- mode: 'analyze',
154
- context: { serviceName: 'api-server' }
155
- });
156
-
157
- console.log(result.markdown);
158
- console.log(result.recommendations);
159
-
160
- // Compare profiles
161
- const diffResult = await diff('base.pb.gz', 'current.pb.gz');
162
- console.log(diffResult.regressions);
163
- ```
164
-
165
- ## Understanding the Output
166
-
167
- ### Hotspots
168
-
169
- Functions ranked by CPU time or memory allocation:
170
- - **Self%**: Time spent in this function only
171
- - **Cum%**: Time spent in this function + its callees
172
- - **Location**: Source file and line number
173
-
174
- ### Recommendations (AI mode)
175
-
176
- Each recommendation includes:
177
- - **Title**: What to do
178
- - **Rationale**: Why (with evidence from the profile)
179
- - **Steps**: How to implement
180
- - **Impact/Risk/Confidence**: Prioritization info
181
-
182
- ### Diff Analysis
183
-
184
- When comparing profiles:
185
- - **Regressions**: Functions that got slower
186
- - **Improvements**: Functions that got faster
187
- - **Call Path Δ**: Which paths contributed to the change
188
-
189
- ## Collecting Profiles
190
-
191
- ### Node.js with @datadog/pprof
192
-
193
- ```typescript
194
- import * as pprof from '@datadog/pprof';
195
- import { writeFileSync } from 'fs';
196
- import { gzipSync } from 'zlib';
197
-
198
- // CPU profiling (30 seconds)
199
- pprof.time.start({ durationMillis: 30000 });
200
- // ... run your workload ...
201
- const profile = await pprof.time.stop();
202
- writeFileSync('cpu.pb.gz', gzipSync(profile.encode()));
203
-
204
- // Heap profiling
205
- pprof.heap.start(512 * 1024, 64);
206
- // ... run your workload ...
207
- const heapProfile = await pprof.heap.profile();
208
- writeFileSync('heap.pb.gz', gzipSync(heapProfile.encode()));
209
- ```
210
-
211
- ## Tips
212
-
213
- 1. **Start with `--format summary`** for quick triage
214
- 2. **Use `--mode convert-only`** when you just need the markdown
215
- 3. **Compare profiles** to find the cause of regressions
216
- 4. **Provide context** (`--service`, `--scenario`) for better AI recommendations
217
- 5. **High self%** = function is doing expensive work directly
218
- 6. **High cum%** = function is on a hot path (may be calling slow functions)
219
-
220
- ## Requirements
221
-
222
- - Node.js >= 22.6.0
223
- - For AI analysis: Set `OPENAI_API_KEY` or configure LLM provider
224
- - CPU profiling uses bundled `@datadog/pprof` (native module); supported on common platforms
225
-
226
- ## Troubleshooting
227
-
228
- ### "No symbols found"
229
- The profile may be from a production build without debug info. The analysis still works but function names may be mangled.
230
-
231
- ### "Native code dominates"
232
- If native functions (like `JSON.parse`) are top hotspots, consider:
233
- - Using streaming parsers for large JSON
234
- - Caching parsed results
235
- - Using binary formats like Protocol Buffers
236
-
237
- ### "Low sample count"
238
- Run the profiler longer to get more samples for statistical significance.
@@ -1,27 +0,0 @@
1
- /**
2
- * HTTP API server for perf-skill
3
- */
4
- import { type FastifyInstance } from "fastify";
5
- import { analyze, diff } from "../index.js";
6
- export interface ServerOptions {
7
- port?: number;
8
- host?: string;
9
- maxFileSize?: number;
10
- enableCors?: boolean;
11
- corsOrigin?: string | string[] | boolean;
12
- enableHelmet?: boolean;
13
- enableRateLimit?: boolean;
14
- rateLimitMax?: number;
15
- rateLimitWindowMs?: number;
16
- analyzeFn?: typeof analyze;
17
- diffFn?: typeof diff;
18
- }
19
- /**
20
- * Create and configure Fastify server
21
- */
22
- export declare function createServer(options?: ServerOptions): Promise<FastifyInstance>;
23
- /**
24
- * Start the HTTP server
25
- */
26
- export declare function startServer(options?: ServerOptions): Promise<FastifyInstance>;
27
- //# sourceMappingURL=http.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAKxD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAY5C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IACzC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,OAAO,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqSxF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAiBvF"}