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.
- package/.claude-plugin/README.md +48 -0
- package/.claude-plugin/marketplace.json +27 -0
- package/.claude-plugin/plugin.json +21 -0
- package/CLAUDE.md +166 -0
- package/README.md +128 -109
- package/dist/cli/init.d.ts +19 -3
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +108 -11
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/main.js +72 -49
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/platforms.d.ts +28 -0
- package/dist/cli/platforms.d.ts.map +1 -0
- package/dist/cli/platforms.js +238 -0
- package/dist/cli/platforms.js.map +1 -0
- package/dist/cli/template.d.ts +16 -0
- package/dist/cli/template.d.ts.map +1 -0
- package/dist/cli/template.js +157 -0
- package/dist/cli/template.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +71 -36
- package/dist/index.js.map +1 -1
- package/dist/llm/client.d.ts +6 -0
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +11 -2
- package/dist/llm/client.js.map +1 -1
- package/dist/llm/index.d.ts +1 -1
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +1 -1
- package/dist/llm/index.js.map +1 -1
- package/dist/skill/handler.d.ts +7 -0
- package/dist/skill/handler.d.ts.map +1 -1
- package/dist/skill/handler.js +24 -1
- package/dist/skill/handler.js.map +1 -1
- package/dist/skill/manifest.d.ts +4 -0
- package/dist/skill/manifest.d.ts.map +1 -1
- package/dist/skill/manifest.js +60 -39
- package/dist/skill/manifest.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -10
- package/skills/perf-skill/SKILL.md +194 -0
- package/SKILL.md +0 -238
- package/dist/server/http.d.ts +0 -27
- package/dist/server/http.d.ts.map +0 -1
- package/dist/server/http.js +0 -285
- package/dist/server/http.js.map +0 -1
- package/dist/server/utils.d.ts +0 -15
- package/dist/server/utils.d.ts.map +0 -1
- package/dist/server/utils.js +0 -71
- package/dist/server/utils.js.map +0 -1
package/dist/server/http.js
DELETED
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP API server for perf-skill
|
|
3
|
-
*/
|
|
4
|
-
import Fastify from "fastify";
|
|
5
|
-
import multipart from "@fastify/multipart";
|
|
6
|
-
import cors from "@fastify/cors";
|
|
7
|
-
import helmet from "@fastify/helmet";
|
|
8
|
-
import rateLimit from "@fastify/rate-limit";
|
|
9
|
-
import { analyze, diff } from "../index.js";
|
|
10
|
-
import { logger } from "../utils/logger.js";
|
|
11
|
-
import { checkSizeLimit, DEFAULT_LIMITS } from "../utils/limits.js";
|
|
12
|
-
import { cleanupUploadedFiles, parseOptionsField, parseBoolean, parseNumber, resolveMultipartFile, } from "./utils.js";
|
|
13
|
-
/**
|
|
14
|
-
* Create and configure Fastify server
|
|
15
|
-
*/
|
|
16
|
-
export async function createServer(options = {}) {
|
|
17
|
-
const server = Fastify({
|
|
18
|
-
logger: process.env.LOG_FORMAT === "json",
|
|
19
|
-
});
|
|
20
|
-
const analyzeFn = options.analyzeFn ?? analyze;
|
|
21
|
-
const diffFn = options.diffFn ?? diff;
|
|
22
|
-
const corsEnabled = options.enableCors ?? parseBoolean(process.env.CORS_ENABLED, true);
|
|
23
|
-
const helmetEnabled = options.enableHelmet ?? parseBoolean(process.env.HELMET_ENABLED, true);
|
|
24
|
-
const rateLimitEnabled = options.enableRateLimit ?? parseBoolean(process.env.RATE_LIMIT_ENABLED, true);
|
|
25
|
-
if (corsEnabled) {
|
|
26
|
-
const originValue = options.corsOrigin ?? process.env.CORS_ORIGIN ?? true;
|
|
27
|
-
const origin = typeof originValue === "string"
|
|
28
|
-
? originValue === "*"
|
|
29
|
-
? true
|
|
30
|
-
: originValue.split(",").map((item) => item.trim()).filter(Boolean)
|
|
31
|
-
: originValue;
|
|
32
|
-
await server.register(cors, { origin });
|
|
33
|
-
}
|
|
34
|
-
if (helmetEnabled) {
|
|
35
|
-
await server.register(helmet);
|
|
36
|
-
}
|
|
37
|
-
if (rateLimitEnabled) {
|
|
38
|
-
const max = options.rateLimitMax ?? parseNumber(process.env.RATE_LIMIT_MAX, 60);
|
|
39
|
-
const timeWindow = options.rateLimitWindowMs ?? parseNumber(process.env.RATE_LIMIT_WINDOW_MS, 60_000);
|
|
40
|
-
if (max > 0) {
|
|
41
|
-
await server.register(rateLimit, { max, timeWindow });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
// Register multipart plugin for file uploads
|
|
45
|
-
await server.register(multipart, {
|
|
46
|
-
attachFieldsToBody: true,
|
|
47
|
-
limits: {
|
|
48
|
-
fileSize: options.maxFileSize ?? DEFAULT_LIMITS.maxProfileBytes,
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
// Health check
|
|
52
|
-
server.get("/health", async () => {
|
|
53
|
-
return { status: "ok", timestamp: new Date().toISOString() };
|
|
54
|
-
});
|
|
55
|
-
// API info
|
|
56
|
-
server.get("/v1", async () => {
|
|
57
|
-
return {
|
|
58
|
-
name: "perf-skill",
|
|
59
|
-
version: "1.0.0",
|
|
60
|
-
endpoints: {
|
|
61
|
-
analyze: "POST /v1/pprof/analyze",
|
|
62
|
-
diff: "POST /v1/pprof/diff",
|
|
63
|
-
convert: "POST /v1/pprof/convert",
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
});
|
|
67
|
-
// Analyze endpoint
|
|
68
|
-
server.post("/v1/pprof/analyze", async (request, reply) => {
|
|
69
|
-
const startTime = performance.now();
|
|
70
|
-
try {
|
|
71
|
-
// Handle multipart file upload
|
|
72
|
-
const data = await resolveMultipartFile(request, "file");
|
|
73
|
-
if (!data) {
|
|
74
|
-
return reply.status(400).send({
|
|
75
|
-
success: false,
|
|
76
|
-
error: {
|
|
77
|
-
code: "MISSING_FILE",
|
|
78
|
-
message: "Profile file is required",
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
const profileBuffer = await data.toBuffer();
|
|
83
|
-
checkSizeLimit(profileBuffer, DEFAULT_LIMITS.maxProfileBytes, "Profile");
|
|
84
|
-
let options;
|
|
85
|
-
try {
|
|
86
|
-
options = parseOptionsField(request.body?.options);
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
return reply.status(400).send({
|
|
90
|
-
success: false,
|
|
91
|
-
error: {
|
|
92
|
-
code: "INVALID_OPTIONS",
|
|
93
|
-
message: error instanceof Error ? error.message : "Invalid options",
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
// Default to not including source in server mode for security
|
|
98
|
-
if (options.includeSource === undefined) {
|
|
99
|
-
options.includeSource = false;
|
|
100
|
-
}
|
|
101
|
-
logger.info("Analyze request received", {
|
|
102
|
-
filename: data.filename,
|
|
103
|
-
size: profileBuffer.length,
|
|
104
|
-
mode: options.mode,
|
|
105
|
-
});
|
|
106
|
-
const result = await analyzeFn(profileBuffer, options);
|
|
107
|
-
const response = {
|
|
108
|
-
success: true,
|
|
109
|
-
data: result,
|
|
110
|
-
};
|
|
111
|
-
logger.info("Analyze request completed", {
|
|
112
|
-
durationMs: Math.round(performance.now() - startTime),
|
|
113
|
-
hotspotsCount: result.hotspots.length,
|
|
114
|
-
});
|
|
115
|
-
return response;
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
logger.error("Analyze request failed", {
|
|
119
|
-
error: error instanceof Error ? error.message : String(error),
|
|
120
|
-
});
|
|
121
|
-
return reply.status(500).send({
|
|
122
|
-
success: false,
|
|
123
|
-
error: {
|
|
124
|
-
code: "ANALYSIS_ERROR",
|
|
125
|
-
message: error instanceof Error ? error.message : "Analysis failed",
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
// Convert-only endpoint (no LLM)
|
|
131
|
-
server.post("/v1/pprof/convert", async (request, reply) => {
|
|
132
|
-
try {
|
|
133
|
-
const data = await resolveMultipartFile(request, "file");
|
|
134
|
-
if (!data) {
|
|
135
|
-
return reply.status(400).send({
|
|
136
|
-
success: false,
|
|
137
|
-
error: {
|
|
138
|
-
code: "MISSING_FILE",
|
|
139
|
-
message: "Profile file is required",
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
const profileBuffer = await data.toBuffer();
|
|
144
|
-
checkSizeLimit(profileBuffer, DEFAULT_LIMITS.maxProfileBytes, "Profile");
|
|
145
|
-
let parsedOptions;
|
|
146
|
-
try {
|
|
147
|
-
parsedOptions = parseOptionsField(request.body?.options);
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
return reply.status(400).send({
|
|
151
|
-
success: false,
|
|
152
|
-
error: {
|
|
153
|
-
code: "INVALID_OPTIONS",
|
|
154
|
-
message: error instanceof Error ? error.message : "Invalid options",
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
const options = {
|
|
159
|
-
...parsedOptions,
|
|
160
|
-
mode: "convert-only",
|
|
161
|
-
includeSource: false,
|
|
162
|
-
};
|
|
163
|
-
const result = await analyzeFn(profileBuffer, options);
|
|
164
|
-
return {
|
|
165
|
-
success: true,
|
|
166
|
-
data: result,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
return reply.status(500).send({
|
|
171
|
-
success: false,
|
|
172
|
-
error: {
|
|
173
|
-
code: "CONVERT_ERROR",
|
|
174
|
-
message: error instanceof Error ? error.message : "Conversion failed",
|
|
175
|
-
},
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
// Diff endpoint
|
|
180
|
-
server.post("/v1/pprof/diff", async (request, reply) => {
|
|
181
|
-
const startTime = performance.now();
|
|
182
|
-
let files;
|
|
183
|
-
try {
|
|
184
|
-
// Expect two files: base and current
|
|
185
|
-
files = await request.saveRequestFiles();
|
|
186
|
-
if (files.length < 2) {
|
|
187
|
-
return reply.status(400).send({
|
|
188
|
-
success: false,
|
|
189
|
-
error: {
|
|
190
|
-
code: "MISSING_FILES",
|
|
191
|
-
message: "Two profile files required (base and current)",
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
const baseFile = files.find(f => f.fieldname === "base") || files[0];
|
|
196
|
-
const currentFile = files.find(f => f.fieldname === "current") || files[1];
|
|
197
|
-
const { readFile } = await import("node:fs/promises");
|
|
198
|
-
const baseBuffer = await readFile(baseFile.filepath);
|
|
199
|
-
const currentBuffer = await readFile(currentFile.filepath);
|
|
200
|
-
checkSizeLimit(baseBuffer, DEFAULT_LIMITS.maxProfileBytes, "Base profile");
|
|
201
|
-
checkSizeLimit(currentBuffer, DEFAULT_LIMITS.maxProfileBytes, "Current profile");
|
|
202
|
-
let options;
|
|
203
|
-
try {
|
|
204
|
-
options = parseOptionsField(request.body?.options);
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
return reply.status(400).send({
|
|
208
|
-
success: false,
|
|
209
|
-
error: {
|
|
210
|
-
code: "INVALID_OPTIONS",
|
|
211
|
-
message: error instanceof Error ? error.message : "Invalid options",
|
|
212
|
-
},
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
logger.info("Diff request received", {
|
|
216
|
-
baseSize: baseBuffer.length,
|
|
217
|
-
currentSize: currentBuffer.length,
|
|
218
|
-
});
|
|
219
|
-
const result = await diffFn(baseBuffer, currentBuffer, options);
|
|
220
|
-
logger.info("Diff request completed", {
|
|
221
|
-
durationMs: Math.round(performance.now() - startTime),
|
|
222
|
-
regressions: result.regressions.length,
|
|
223
|
-
improvements: result.improvements.length,
|
|
224
|
-
});
|
|
225
|
-
return {
|
|
226
|
-
success: true,
|
|
227
|
-
data: result,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
logger.error("Diff request failed", {
|
|
232
|
-
error: error instanceof Error ? error.message : String(error),
|
|
233
|
-
});
|
|
234
|
-
return reply.status(500).send({
|
|
235
|
-
success: false,
|
|
236
|
-
error: {
|
|
237
|
-
code: "DIFF_ERROR",
|
|
238
|
-
message: error instanceof Error ? error.message : "Diff analysis failed",
|
|
239
|
-
},
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
finally {
|
|
243
|
-
if (files) {
|
|
244
|
-
await cleanupUploadedFiles(files);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
// Error handler
|
|
249
|
-
server.setErrorHandler((error, request, reply) => {
|
|
250
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
251
|
-
logger.error("Server error", {
|
|
252
|
-
error: message,
|
|
253
|
-
url: request.url,
|
|
254
|
-
});
|
|
255
|
-
reply.status(500).send({
|
|
256
|
-
success: false,
|
|
257
|
-
error: {
|
|
258
|
-
code: "INTERNAL_ERROR",
|
|
259
|
-
message: "Internal server error",
|
|
260
|
-
},
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
return server;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Start the HTTP server
|
|
267
|
-
*/
|
|
268
|
-
export async function startServer(options = {}) {
|
|
269
|
-
const server = await createServer(options);
|
|
270
|
-
const port = options.port ?? 3000;
|
|
271
|
-
const host = options.host ?? "0.0.0.0";
|
|
272
|
-
try {
|
|
273
|
-
await server.listen({ port, host });
|
|
274
|
-
console.log(`perf-skill server listening on http://${host}:${port}`);
|
|
275
|
-
console.log(`API docs: http://${host}:${port}/v1`);
|
|
276
|
-
return server;
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
logger.error("Failed to start server", {
|
|
280
|
-
error: error instanceof Error ? error.message : String(error),
|
|
281
|
-
});
|
|
282
|
-
throw error;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
//# sourceMappingURL=http.js.map
|
package/dist/server/http.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"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"}
|
package/dist/server/utils.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server utilities for multipart handling
|
|
3
|
-
*/
|
|
4
|
-
import type { MultipartFile } from "@fastify/multipart";
|
|
5
|
-
export declare function parseOptionsField<T extends object>(input: unknown): T;
|
|
6
|
-
export declare function cleanupUploadedFiles(files: Array<{
|
|
7
|
-
filepath?: string | null;
|
|
8
|
-
}>): Promise<void>;
|
|
9
|
-
export declare function resolveMultipartFile(request: {
|
|
10
|
-
file: () => Promise<MultipartFile | undefined>;
|
|
11
|
-
body?: Record<string, unknown>;
|
|
12
|
-
}, fieldName: string): Promise<MultipartFile | undefined>;
|
|
13
|
-
export declare function parseBoolean(value: string | undefined, defaultValue: boolean): boolean;
|
|
14
|
-
export declare function parseNumber(value: string | undefined, defaultValue: number): number;
|
|
15
|
-
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/server/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CA2BrE;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,KAAK,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC3F,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAapC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAMtF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAInF"}
|
package/dist/server/utils.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server utilities for multipart handling
|
|
3
|
-
*/
|
|
4
|
-
import { rm } from "node:fs/promises";
|
|
5
|
-
import { logger } from "../utils/logger.js";
|
|
6
|
-
export function parseOptionsField(input) {
|
|
7
|
-
if (input === undefined || input === null) {
|
|
8
|
-
return {};
|
|
9
|
-
}
|
|
10
|
-
if (typeof input === "string") {
|
|
11
|
-
const trimmed = input.trim();
|
|
12
|
-
if (!trimmed) {
|
|
13
|
-
return {};
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
return JSON.parse(trimmed);
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
throw new Error(`Invalid options JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
if (typeof input === "object") {
|
|
23
|
-
if (input && "value" in input) {
|
|
24
|
-
return parseOptionsField(input.value);
|
|
25
|
-
}
|
|
26
|
-
return input;
|
|
27
|
-
}
|
|
28
|
-
throw new Error("Invalid options field type");
|
|
29
|
-
}
|
|
30
|
-
export async function cleanupUploadedFiles(files) {
|
|
31
|
-
const paths = files
|
|
32
|
-
.map((file) => file.filepath)
|
|
33
|
-
.filter((path) => Boolean(path));
|
|
34
|
-
const results = await Promise.allSettled(paths.map((path) => rm(path, { force: true })));
|
|
35
|
-
results.forEach((result, index) => {
|
|
36
|
-
if (result.status === "rejected") {
|
|
37
|
-
logger.warn("Failed to cleanup uploaded file", {
|
|
38
|
-
path: paths[index],
|
|
39
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
export async function resolveMultipartFile(request, fieldName) {
|
|
45
|
-
const body = request.body;
|
|
46
|
-
const entry = body?.[fieldName];
|
|
47
|
-
if (Array.isArray(entry)) {
|
|
48
|
-
return entry[0];
|
|
49
|
-
}
|
|
50
|
-
if (entry && typeof entry === "object" && entry.type === "file") {
|
|
51
|
-
return entry;
|
|
52
|
-
}
|
|
53
|
-
return request.file();
|
|
54
|
-
}
|
|
55
|
-
export function parseBoolean(value, defaultValue) {
|
|
56
|
-
if (value === undefined)
|
|
57
|
-
return defaultValue;
|
|
58
|
-
const normalized = value.trim().toLowerCase();
|
|
59
|
-
if (["1", "true", "yes", "on"].includes(normalized))
|
|
60
|
-
return true;
|
|
61
|
-
if (["0", "false", "no", "off"].includes(normalized))
|
|
62
|
-
return false;
|
|
63
|
-
return defaultValue;
|
|
64
|
-
}
|
|
65
|
-
export function parseNumber(value, defaultValue) {
|
|
66
|
-
if (value === undefined)
|
|
67
|
-
return defaultValue;
|
|
68
|
-
const parsed = Number(value);
|
|
69
|
-
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
70
|
-
}
|
|
71
|
-
//# sourceMappingURL=utils.js.map
|
package/dist/server/utils.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/server/utils.ts"],"names":[],"mappings":"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"}
|