perf-skill 0.0.1 → 0.2.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.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +404 -0
  3. package/SKILL.md +238 -0
  4. package/dist/cli/init.d.ts +29 -0
  5. package/dist/cli/init.d.ts.map +1 -0
  6. package/dist/cli/init.js +139 -0
  7. package/dist/cli/init.js.map +1 -0
  8. package/dist/cli/main.d.ts +6 -0
  9. package/dist/cli/main.d.ts.map +1 -0
  10. package/dist/cli/main.js +389 -0
  11. package/dist/cli/main.js.map +1 -0
  12. package/dist/cli/options.d.ts +37 -0
  13. package/dist/cli/options.d.ts.map +1 -0
  14. package/dist/cli/options.js +54 -0
  15. package/dist/cli/options.js.map +1 -0
  16. package/dist/convert/converter.d.ts +39 -0
  17. package/dist/convert/converter.d.ts.map +1 -0
  18. package/dist/convert/converter.js +99 -0
  19. package/dist/convert/converter.js.map +1 -0
  20. package/dist/convert/extract.d.ts +32 -0
  21. package/dist/convert/extract.d.ts.map +1 -0
  22. package/dist/convert/extract.js +235 -0
  23. package/dist/convert/extract.js.map +1 -0
  24. package/dist/convert/index.d.ts +7 -0
  25. package/dist/convert/index.d.ts.map +1 -0
  26. package/dist/convert/index.js +7 -0
  27. package/dist/convert/index.js.map +1 -0
  28. package/dist/convert/sanitize.d.ts +60 -0
  29. package/dist/convert/sanitize.d.ts.map +1 -0
  30. package/dist/convert/sanitize.js +169 -0
  31. package/dist/convert/sanitize.js.map +1 -0
  32. package/dist/diff/engine.d.ts +76 -0
  33. package/dist/diff/engine.d.ts.map +1 -0
  34. package/dist/diff/engine.js +386 -0
  35. package/dist/diff/engine.js.map +1 -0
  36. package/dist/diff/index.d.ts +6 -0
  37. package/dist/diff/index.d.ts.map +1 -0
  38. package/dist/diff/index.js +6 -0
  39. package/dist/diff/index.js.map +1 -0
  40. package/dist/diff/markdown.d.ts +16 -0
  41. package/dist/diff/markdown.d.ts.map +1 -0
  42. package/dist/diff/markdown.js +342 -0
  43. package/dist/diff/markdown.js.map +1 -0
  44. package/dist/index.d.ts +52 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +247 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/llm/client.d.ts +39 -0
  49. package/dist/llm/client.d.ts.map +1 -0
  50. package/dist/llm/client.js +270 -0
  51. package/dist/llm/client.js.map +1 -0
  52. package/dist/llm/index.d.ts +8 -0
  53. package/dist/llm/index.d.ts.map +1 -0
  54. package/dist/llm/index.js +8 -0
  55. package/dist/llm/index.js.map +1 -0
  56. package/dist/llm/prompt.d.ts +32 -0
  57. package/dist/llm/prompt.d.ts.map +1 -0
  58. package/dist/llm/prompt.js +146 -0
  59. package/dist/llm/prompt.js.map +1 -0
  60. package/dist/llm/schema.d.ts +150 -0
  61. package/dist/llm/schema.d.ts.map +1 -0
  62. package/dist/llm/schema.js +131 -0
  63. package/dist/llm/schema.js.map +1 -0
  64. package/dist/llm/validate.d.ts +33 -0
  65. package/dist/llm/validate.d.ts.map +1 -0
  66. package/dist/llm/validate.js +241 -0
  67. package/dist/llm/validate.js.map +1 -0
  68. package/dist/profile/duration.d.ts +2 -0
  69. package/dist/profile/duration.d.ts.map +1 -0
  70. package/dist/profile/duration.js +24 -0
  71. package/dist/profile/duration.js.map +1 -0
  72. package/dist/profile/preload.d.ts +2 -0
  73. package/dist/profile/preload.d.ts.map +1 -0
  74. package/dist/profile/preload.js +100 -0
  75. package/dist/profile/preload.js.map +1 -0
  76. package/dist/profile/runner.d.ts +22 -0
  77. package/dist/profile/runner.d.ts.map +1 -0
  78. package/dist/profile/runner.js +88 -0
  79. package/dist/profile/runner.js.map +1 -0
  80. package/dist/server/http.d.ts +27 -0
  81. package/dist/server/http.d.ts.map +1 -0
  82. package/dist/server/http.js +285 -0
  83. package/dist/server/http.js.map +1 -0
  84. package/dist/server/utils.d.ts +15 -0
  85. package/dist/server/utils.d.ts.map +1 -0
  86. package/dist/server/utils.js +71 -0
  87. package/dist/server/utils.js.map +1 -0
  88. package/dist/skill/handler.d.ts +77 -0
  89. package/dist/skill/handler.d.ts.map +1 -0
  90. package/dist/skill/handler.js +91 -0
  91. package/dist/skill/handler.js.map +1 -0
  92. package/dist/skill/index.d.ts +6 -0
  93. package/dist/skill/index.d.ts.map +1 -0
  94. package/dist/skill/index.js +6 -0
  95. package/dist/skill/index.js.map +1 -0
  96. package/dist/skill/manifest.d.ts +17 -0
  97. package/dist/skill/manifest.d.ts.map +1 -0
  98. package/dist/skill/manifest.js +231 -0
  99. package/dist/skill/manifest.js.map +1 -0
  100. package/dist/types.d.ts +260 -0
  101. package/dist/types.d.ts.map +1 -0
  102. package/dist/types.js +5 -0
  103. package/dist/types.js.map +1 -0
  104. package/dist/utils/fs.d.ts +52 -0
  105. package/dist/utils/fs.d.ts.map +1 -0
  106. package/dist/utils/fs.js +106 -0
  107. package/dist/utils/fs.js.map +1 -0
  108. package/dist/utils/index.d.ts +7 -0
  109. package/dist/utils/index.d.ts.map +1 -0
  110. package/dist/utils/index.js +7 -0
  111. package/dist/utils/index.js.map +1 -0
  112. package/dist/utils/limits.d.ts +38 -0
  113. package/dist/utils/limits.d.ts.map +1 -0
  114. package/dist/utils/limits.js +86 -0
  115. package/dist/utils/limits.js.map +1 -0
  116. package/dist/utils/logger.d.ts +21 -0
  117. package/dist/utils/logger.d.ts.map +1 -0
  118. package/dist/utils/logger.js +82 -0
  119. package/dist/utils/logger.js.map +1 -0
  120. package/package.json +70 -6
@@ -0,0 +1,106 @@
1
+ /**
2
+ * File system utilities for temporary file management
3
+ */
4
+ import { writeFile, rm, readFile, mkdir } from "node:fs/promises";
5
+ import { tmpdir } from "node:os";
6
+ import { join, dirname } from "node:path";
7
+ import { randomUUID } from "node:crypto";
8
+ import { gunzipSync, gzipSync } from "node:zlib";
9
+ import { isGzip } from "./limits.js";
10
+ /**
11
+ * Generate a unique temporary file path
12
+ */
13
+ export function getTempPath(prefix = "pprof", ext = ".pb.gz") {
14
+ return join(tmpdir(), `${prefix}-${randomUUID()}${ext}`);
15
+ }
16
+ /**
17
+ * Write data to a temporary file and return the path
18
+ */
19
+ export async function writeToTemp(data, prefix = "pprof", ext = ".pb.gz") {
20
+ const tempPath = getTempPath(prefix, ext);
21
+ await writeFile(tempPath, data);
22
+ return tempPath;
23
+ }
24
+ /**
25
+ * Safely remove a file (ignores errors)
26
+ */
27
+ export async function safeRemove(path) {
28
+ try {
29
+ await rm(path, { force: true });
30
+ }
31
+ catch {
32
+ // Ignore removal errors
33
+ }
34
+ }
35
+ /**
36
+ * Execute a function with a temporary file, ensuring cleanup
37
+ */
38
+ export async function withTempFile(data, fn, prefix = "pprof", ext = ".pb.gz") {
39
+ const tempPath = await writeToTemp(data, prefix, ext);
40
+ try {
41
+ return await fn(tempPath);
42
+ }
43
+ finally {
44
+ await safeRemove(tempPath);
45
+ }
46
+ }
47
+ /**
48
+ * Read and decompress a gzipped file
49
+ */
50
+ export async function readGzipFile(path, maxOutputBytes) {
51
+ const data = await readFile(path);
52
+ return decompressIfNeeded(data, maxOutputBytes);
53
+ }
54
+ /**
55
+ * Decompress data if gzipped
56
+ */
57
+ export function decompressIfNeeded(data, maxOutputBytes) {
58
+ if (isGzip(data)) {
59
+ if (maxOutputBytes) {
60
+ return gunzipSync(data, { maxOutputLength: maxOutputBytes });
61
+ }
62
+ return gunzipSync(data);
63
+ }
64
+ return Buffer.from(data);
65
+ }
66
+ /**
67
+ * Compress data with gzip
68
+ */
69
+ export function compressGzip(data) {
70
+ return gzipSync(data);
71
+ }
72
+ /**
73
+ * Pick a profile file extension based on compression
74
+ */
75
+ export function getProfileExtension(data) {
76
+ return isGzip(data) ? ".pb.gz" : ".pb";
77
+ }
78
+ /**
79
+ * Ensure directory exists
80
+ */
81
+ export async function ensureDir(path) {
82
+ const dir = dirname(path);
83
+ await mkdir(dir, { recursive: true });
84
+ }
85
+ /**
86
+ * Convert base64 to Buffer
87
+ */
88
+ export function base64ToBuffer(base64) {
89
+ return Buffer.from(base64, "base64");
90
+ }
91
+ /**
92
+ * Convert Buffer to base64
93
+ */
94
+ export function bufferToBase64(buffer) {
95
+ return Buffer.from(buffer).toString("base64");
96
+ }
97
+ /**
98
+ * Load profile from path or base64
99
+ */
100
+ export async function loadProfile(input, encoding = "path") {
101
+ if (encoding === "base64") {
102
+ return base64ToBuffer(input);
103
+ }
104
+ return readFile(input);
105
+ }
106
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Utilities module exports
3
+ */
4
+ export { logger, setLogLevel, type LogLevel, } from "./logger.js";
5
+ export { DEFAULT_LIMITS, resolveLimits, checkSizeLimit, checkCharLimit, formatBytes, formatDuration, withTimeout, isGzip, validateProfileExtension, } from "./limits.js";
6
+ export { getTempPath, writeToTemp, safeRemove, withTempFile, readGzipFile, decompressIfNeeded, compressGzip, getProfileExtension, ensureDir, base64ToBuffer, bufferToBase64, loadProfile, } from "./fs.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EACN,WAAW,EACX,KAAK,QAAQ,GACd,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,EACd,cAAc,EACd,WAAW,EACX,cAAc,EACd,WAAW,EACX,MAAM,EACN,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Utilities module exports
3
+ */
4
+ export { logger, setLogLevel, } from "./logger.js";
5
+ export { DEFAULT_LIMITS, resolveLimits, checkSizeLimit, checkCharLimit, formatBytes, formatDuration, withTimeout, isGzip, validateProfileExtension, } from "./limits.js";
6
+ export { getTempPath, writeToTemp, safeRemove, withTempFile, readGzipFile, decompressIfNeeded, compressGzip, getProfileExtension, ensureDir, base64ToBuffer, bufferToBase64, loadProfile, } from "./fs.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EACN,WAAW,GAEZ,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,EACd,cAAc,EACd,WAAW,EACX,cAAc,EACd,WAAW,EACX,MAAM,EACN,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Resource limits and validation
3
+ */
4
+ import type { ResourceLimits } from "../types.js";
5
+ export declare const DEFAULT_LIMITS: Required<ResourceLimits>;
6
+ /**
7
+ * Merge user limits with defaults
8
+ */
9
+ export declare function resolveLimits(userLimits?: ResourceLimits): Required<ResourceLimits>;
10
+ /**
11
+ * Check if a buffer exceeds size limit
12
+ */
13
+ export declare function checkSizeLimit(data: Uint8Array | Buffer, maxBytes: number, label?: string): void;
14
+ /**
15
+ * Check if content exceeds character limit
16
+ */
17
+ export declare function checkCharLimit(content: string, maxChars: number, label?: string): void;
18
+ /**
19
+ * Format bytes to human-readable string
20
+ */
21
+ export declare function formatBytes(bytes: number): string;
22
+ /**
23
+ * Format duration in milliseconds
24
+ */
25
+ export declare function formatDuration(ms: number): string;
26
+ /**
27
+ * Create a timeout promise
28
+ */
29
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number, message?: string): Promise<T>;
30
+ /**
31
+ * Gzip magic number check
32
+ */
33
+ export declare function isGzip(data: Uint8Array | Buffer): boolean;
34
+ /**
35
+ * Validate profile file extension
36
+ */
37
+ export declare function validateProfileExtension(filename: string): void;
38
+ //# sourceMappingURL=limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/utils/limits.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,cAAc,CAMnD,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC,CAKnF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,GAAG,MAAM,EACzB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAe,GACrB,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAkB,GACxB,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,MAA8B,GACtC,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAU/D"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Resource limits and validation
3
+ */
4
+ // Default limits
5
+ export const DEFAULT_LIMITS = {
6
+ maxProfileBytes: 50 * 1024 * 1024, // 50MB compressed
7
+ maxDecompressedBytes: 200 * 1024 * 1024, // 200MB uncompressed
8
+ maxMarkdownChars: 200_000, // 200k chars
9
+ maxSourceLinesPerFile: 50, // lines per source snippet
10
+ timeoutMs: 60_000, // 60 seconds
11
+ };
12
+ /**
13
+ * Merge user limits with defaults
14
+ */
15
+ export function resolveLimits(userLimits) {
16
+ return {
17
+ ...DEFAULT_LIMITS,
18
+ ...userLimits,
19
+ };
20
+ }
21
+ /**
22
+ * Check if a buffer exceeds size limit
23
+ */
24
+ export function checkSizeLimit(data, maxBytes, label = "file") {
25
+ if (data.length > maxBytes) {
26
+ throw new Error(`${label} size (${formatBytes(data.length)}) exceeds limit (${formatBytes(maxBytes)})`);
27
+ }
28
+ }
29
+ /**
30
+ * Check if content exceeds character limit
31
+ */
32
+ export function checkCharLimit(content, maxChars, label = "content") {
33
+ if (content.length > maxChars) {
34
+ throw new Error(`${label} length (${content.length} chars) exceeds limit (${maxChars} chars)`);
35
+ }
36
+ }
37
+ /**
38
+ * Format bytes to human-readable string
39
+ */
40
+ export function formatBytes(bytes) {
41
+ if (bytes < 1024)
42
+ return `${bytes} B`;
43
+ if (bytes < 1024 * 1024)
44
+ return `${(bytes / 1024).toFixed(1)} KB`;
45
+ if (bytes < 1024 * 1024 * 1024)
46
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
47
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
48
+ }
49
+ /**
50
+ * Format duration in milliseconds
51
+ */
52
+ export function formatDuration(ms) {
53
+ if (ms < 1000)
54
+ return `${Math.round(ms)}ms`;
55
+ if (ms < 60_000)
56
+ return `${(ms / 1000).toFixed(1)}s`;
57
+ return `${(ms / 60_000).toFixed(1)}m`;
58
+ }
59
+ /**
60
+ * Create a timeout promise
61
+ */
62
+ export function withTimeout(promise, ms, message = "Operation timed out") {
63
+ return Promise.race([
64
+ promise,
65
+ new Promise((_, reject) => {
66
+ setTimeout(() => reject(new Error(`${message} after ${formatDuration(ms)}`)), ms);
67
+ }),
68
+ ]);
69
+ }
70
+ /**
71
+ * Gzip magic number check
72
+ */
73
+ export function isGzip(data) {
74
+ return data.length >= 2 && data[0] === 0x1f && data[1] === 0x8b;
75
+ }
76
+ /**
77
+ * Validate profile file extension
78
+ */
79
+ export function validateProfileExtension(filename) {
80
+ const validExtensions = [".pb.gz", ".pprof", ".pb"];
81
+ const hasValidExt = validExtensions.some((ext) => filename.toLowerCase().endsWith(ext));
82
+ if (!hasValidExt) {
83
+ throw new Error(`Invalid profile file extension. Expected: ${validExtensions.join(", ")}`);
84
+ }
85
+ }
86
+ //# sourceMappingURL=limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/utils/limits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Simple structured logger for observability
3
+ */
4
+ export type LogLevel = "debug" | "info" | "warn" | "error";
5
+ export declare function setLogLevel(level: LogLevel): void;
6
+ export declare const logger: {
7
+ debug: (message: string, meta?: Record<string, unknown>) => void;
8
+ info: (message: string, meta?: Record<string, unknown>) => void;
9
+ warn: (message: string, meta?: Record<string, unknown>) => void;
10
+ error: (message: string, meta?: Record<string, unknown>) => void;
11
+ /** Log with timing measurement */
12
+ time: <T>(label: string, fn: () => T) => T;
13
+ /** Create a child logger with default metadata */
14
+ child: (defaultMeta: Record<string, unknown>) => {
15
+ debug: (message: string, meta?: Record<string, unknown>) => void;
16
+ info: (message: string, meta?: Record<string, unknown>) => void;
17
+ warn: (message: string, meta?: Record<string, unknown>) => void;
18
+ error: (message: string, meta?: Record<string, unknown>) => void;
19
+ };
20
+ };
21
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAkB3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEjD;AAuCD,eAAO,MAAM,MAAM;qBACA,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;oBACvC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;oBACtC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;qBACrC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEvD,kCAAkC;WAC3B,CAAC,SAAS,MAAM,MAAM,MAAM,CAAC,KAAG,CAAC;IAqBxC,kDAAkD;yBAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;yBACzB,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;wBAEvC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;wBAEtC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;yBAErC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;CAG1D,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Simple structured logger for observability
3
+ */
4
+ const LOG_LEVELS = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ };
10
+ let currentLevel = process.env.LOG_LEVEL || "info";
11
+ export function setLogLevel(level) {
12
+ currentLevel = level;
13
+ }
14
+ function shouldLog(level) {
15
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
16
+ }
17
+ function formatLog(entry) {
18
+ if (process.env.LOG_FORMAT === "json") {
19
+ return JSON.stringify(entry);
20
+ }
21
+ const { level, message, timestamp, ...rest } = entry;
22
+ const extras = Object.keys(rest).length > 0
23
+ ? ` ${JSON.stringify(rest)}`
24
+ : "";
25
+ return `[${timestamp}] ${level.toUpperCase()}: ${message}${extras}`;
26
+ }
27
+ function log(level, message, meta) {
28
+ if (!shouldLog(level))
29
+ return;
30
+ const entry = {
31
+ level,
32
+ message,
33
+ timestamp: new Date().toISOString(),
34
+ ...meta,
35
+ };
36
+ const output = formatLog(entry);
37
+ if (level === "error") {
38
+ console.error(output);
39
+ }
40
+ else if (level === "warn") {
41
+ console.warn(output);
42
+ }
43
+ else {
44
+ console.log(output);
45
+ }
46
+ }
47
+ export const logger = {
48
+ debug: (message, meta) => log("debug", message, meta),
49
+ info: (message, meta) => log("info", message, meta),
50
+ warn: (message, meta) => log("warn", message, meta),
51
+ error: (message, meta) => log("error", message, meta),
52
+ /** Log with timing measurement */
53
+ time: (label, fn) => {
54
+ const start = performance.now();
55
+ try {
56
+ const result = fn();
57
+ if (result instanceof Promise) {
58
+ return result.then((r) => {
59
+ log("debug", `${label} completed`, { durationMs: Math.round(performance.now() - start) });
60
+ return r;
61
+ }).catch((e) => {
62
+ log("error", `${label} failed`, { durationMs: Math.round(performance.now() - start), error: String(e) });
63
+ throw e;
64
+ });
65
+ }
66
+ log("debug", `${label} completed`, { durationMs: Math.round(performance.now() - start) });
67
+ return result;
68
+ }
69
+ catch (e) {
70
+ log("error", `${label} failed`, { durationMs: Math.round(performance.now() - start), error: String(e) });
71
+ throw e;
72
+ }
73
+ },
74
+ /** Create a child logger with default metadata */
75
+ child: (defaultMeta) => ({
76
+ debug: (message, meta) => log("debug", message, { ...defaultMeta, ...meta }),
77
+ info: (message, meta) => log("info", message, { ...defaultMeta, ...meta }),
78
+ warn: (message, meta) => log("warn", message, { ...defaultMeta, ...meta }),
79
+ error: (message, meta) => log("error", message, { ...defaultMeta, ...meta }),
80
+ }),
81
+ };
82
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,75 @@
1
1
  {
2
2
  "name": "perf-skill",
3
- "version": "0.0.1",
4
- "description": "",
5
- "main": "index.js",
3
+ "version": "0.2.1",
4
+ "description": "AI Skill for pprof profile analysis - convert .pb.gz to Markdown and generate structured performance recommendations",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "perf-skill": "dist/cli/main.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
6
20
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
21
+ "build": "tsc",
22
+ "dev": "tsc --watch",
23
+ "start": "node dist/server/http.js",
24
+ "cli": "node --import tsx src/cli/main.ts",
25
+ "test": "node --test --import tsx 'test/**/*.test.ts'",
26
+ "lint": "eslint src --ext .ts",
27
+ "clean": "rm -rf dist",
28
+ "update-prompts": "node --import tsx scripts/update-prompt-fixtures.ts",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "keywords": [
32
+ "pprof",
33
+ "profiling",
34
+ "performance",
35
+ "ai",
36
+ "llm",
37
+ "markdown",
38
+ "cpu",
39
+ "memory",
40
+ "heap",
41
+ "analysis"
42
+ ],
43
+ "author": "unadlib",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/skillsland/perf-skill.git"
47
+ },
48
+ "license": "MIT",
49
+ "dependencies": {
50
+ "@datadog/pprof": "^5.13.2",
51
+ "@fastify/cors": "^11.2.0",
52
+ "@fastify/helmet": "^13.0.2",
53
+ "@fastify/multipart": "^9.4.0",
54
+ "@fastify/rate-limit": "^10.3.0",
55
+ "commander": "^14.0.3",
56
+ "fastify": "^5.7.3",
57
+ "openai": "^6.17.0",
58
+ "pprof-format": "^2.2.1",
59
+ "pprof-to-md": "^0.2.0",
60
+ "zod": "^4.3.6"
61
+ },
62
+ "devDependencies": {
63
+ "@types/node": "^25.2.0",
64
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
65
+ "@typescript-eslint/parser": "^8.54.0",
66
+ "eslint": "^9.39.2",
67
+ "tsx": "^4.21.0",
68
+ "typescript": "^5.9.3"
8
69
  },
9
- "author": "",
10
- "license": "ISC"
70
+ "files": [
71
+ "dist",
72
+ "SKILL.md",
73
+ "README.md"
74
+ ]
11
75
  }