@stackmemoryai/stackmemory 0.5.52 → 0.5.53

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.
@@ -1,120 +0,0 @@
1
- /**
2
- * Trace Module Export
3
- * Central export for all tracing functionality
4
- */
5
- export { trace, TraceContext, Trace, TraceClass, TraceCritical, } from './debug-trace.js';
6
- export { wrapCommand, wrapProgram, traceStep, traceQuery, traceAPI, } from './cli-trace-wrapper.js';
7
- export { createTracedDatabase, wrapDatabase, getQueryStatistics, createTracedTransaction, } from './db-trace-wrapper.js';
8
- export { TraceLinearAPI, createTracedFetch, wrapGraphQLClient, } from './linear-api-wrapper.js';
9
- /**
10
- * Initialize tracing based on environment configuration
11
- */
12
- export function initializeTracing() {
13
- const config = {
14
- // Main control
15
- DEBUG_TRACE: process.env.DEBUG_TRACE === 'true',
16
- STACKMEMORY_DEBUG: process.env.STACKMEMORY_DEBUG === 'true',
17
- // Output control
18
- TRACE_OUTPUT: process.env.TRACE_OUTPUT || 'console', // console|file|both
19
- TRACE_VERBOSITY: process.env.TRACE_VERBOSITY || 'full', // full|errors|summary
20
- // Content control
21
- TRACE_PARAMS: process.env.TRACE_PARAMS !== 'false', // Include parameters
22
- TRACE_RESULTS: process.env.TRACE_RESULTS !== 'false', // Include results
23
- TRACE_MASK_SENSITIVE: process.env.TRACE_MASK_SENSITIVE !== 'false', // Mask sensitive data
24
- // Performance
25
- TRACE_PERF_THRESHOLD: parseInt(process.env.TRACE_PERF_THRESHOLD || '100'), // ms
26
- TRACE_MEMORY: process.env.TRACE_MEMORY === 'true', // Track memory usage
27
- TRACE_MAX_DEPTH: parseInt(process.env.TRACE_MAX_DEPTH || '20'), // Max call depth
28
- // Database specific
29
- TRACE_DB: process.env.TRACE_DB === 'true', // Enable database tracing
30
- TRACE_DB_SLOW: parseInt(process.env.TRACE_DB_SLOW || '100'), // Slow query threshold
31
- // API specific
32
- TRACE_API: process.env.TRACE_API === 'true', // Enable API tracing
33
- TRACE_API_SLOW: parseInt(process.env.TRACE_API_SLOW || '1000'), // Slow API threshold
34
- };
35
- // Log configuration if debugging is enabled
36
- if (config.DEBUG_TRACE || config.STACKMEMORY_DEBUG) {
37
- console.log('🔍 Trace Configuration:', {
38
- enabled: true,
39
- output: config.TRACE_OUTPUT,
40
- verbosity: config.TRACE_VERBOSITY,
41
- includeParams: config.TRACE_PARAMS,
42
- includeResults: config.TRACE_RESULTS,
43
- maskSensitive: config.TRACE_MASK_SENSITIVE,
44
- performanceThreshold: config.TRACE_PERF_THRESHOLD,
45
- captureMemory: config.TRACE_MEMORY,
46
- maxDepth: config.TRACE_MAX_DEPTH,
47
- database: {
48
- enabled: config.TRACE_DB,
49
- slowThreshold: config.TRACE_DB_SLOW,
50
- },
51
- api: {
52
- enabled: config.TRACE_API,
53
- slowThreshold: config.TRACE_API_SLOW,
54
- },
55
- });
56
- }
57
- }
58
- /**
59
- * Helper to enable tracing for a specific scope
60
- */
61
- export function withTracing(fn, options) {
62
- const originalEnv = process.env.DEBUG_TRACE;
63
- try {
64
- // Temporarily enable tracing
65
- process.env.DEBUG_TRACE = 'true';
66
- // Apply custom options if provided
67
- if (options) {
68
- if (options.output)
69
- process.env.TRACE_OUTPUT = options.output;
70
- if (options.verbosity)
71
- process.env.TRACE_VERBOSITY = options.verbosity;
72
- if (options.includeParams !== undefined) {
73
- process.env.TRACE_PARAMS = String(options.includeParams);
74
- }
75
- if (options.includeResults !== undefined) {
76
- process.env.TRACE_RESULTS = String(options.includeResults);
77
- }
78
- if (options.performanceThreshold !== undefined) {
79
- process.env.TRACE_PERF_THRESHOLD = String(options.performanceThreshold);
80
- }
81
- }
82
- return fn();
83
- }
84
- finally {
85
- // Restore original environment
86
- if (originalEnv === undefined) {
87
- delete process.env.DEBUG_TRACE;
88
- }
89
- else {
90
- process.env.DEBUG_TRACE = originalEnv;
91
- }
92
- }
93
- }
94
- /**
95
- * Quick enable/disable functions for debugging
96
- */
97
- export const enableTracing = () => {
98
- process.env.DEBUG_TRACE = 'true';
99
- console.log('✅ Tracing enabled');
100
- };
101
- export const disableTracing = () => {
102
- delete process.env.DEBUG_TRACE;
103
- console.log('❌ Tracing disabled');
104
- };
105
- export const enableVerboseTracing = () => {
106
- process.env.DEBUG_TRACE = 'true';
107
- process.env.TRACE_VERBOSITY = 'full';
108
- process.env.TRACE_PARAMS = 'true';
109
- process.env.TRACE_RESULTS = 'true';
110
- process.env.TRACE_MEMORY = 'true';
111
- console.log('✅ Verbose tracing enabled');
112
- };
113
- export const enableMinimalTracing = () => {
114
- process.env.DEBUG_TRACE = 'true';
115
- process.env.TRACE_VERBOSITY = 'summary';
116
- process.env.TRACE_PARAMS = 'false';
117
- process.env.TRACE_RESULTS = 'false';
118
- process.env.TRACE_MEMORY = 'false';
119
- console.log('✅ Minimal tracing enabled');
120
- };
@@ -1,204 +0,0 @@
1
- /**
2
- * Linear API Trace Wrapper
3
- * Wraps Linear API client with comprehensive tracing for debugging
4
- */
5
- import { trace } from './debug-trace.js';
6
- import { logger } from '../monitoring/logger.js';
7
- /**
8
- * Decorator to trace Linear API GraphQL calls
9
- */
10
- export function TraceLinearAPI(target, propertyKey, descriptor) {
11
- const originalMethod = descriptor.value;
12
- const isAsync = originalMethod.constructor.name === 'AsyncFunction';
13
- if (isAsync) {
14
- descriptor.value = async function (...args) {
15
- const className = target.constructor.name;
16
- const methodName = `${className}.${propertyKey}`;
17
- // Extract meaningful context from arguments
18
- const context = extractAPIContext(propertyKey, args);
19
- return trace.traceAsync('api', methodName, context, async () => {
20
- const startTime = Date.now();
21
- try {
22
- // Log API call start
23
- logger.debug(`Linear API Call: ${methodName}`, context);
24
- const result = await originalMethod.apply(this, args);
25
- const duration = Date.now() - startTime;
26
- // Log successful completion with timing
27
- logger.info(`Linear API Success: ${methodName}`, {
28
- duration,
29
- resultType: Array.isArray(result) ? `array[${result.length}]` : typeof result,
30
- hasData: result != null,
31
- });
32
- // Warn about slow API calls
33
- if (duration > 1000) {
34
- logger.warn(`Slow Linear API call: ${methodName} took ${duration}ms`, {
35
- ...context,
36
- duration,
37
- });
38
- }
39
- return result;
40
- }
41
- catch (error) {
42
- const duration = Date.now() - startTime;
43
- // Enhanced error logging for API failures
44
- logger.error(`Linear API Failed: ${methodName}`, error, {
45
- ...context,
46
- duration,
47
- errorCode: error.code,
48
- statusCode: error.statusCode,
49
- graphQLErrors: error.errors,
50
- });
51
- // Add debugging hints based on error type
52
- if (error.message?.includes('rate limit')) {
53
- logger.warn('Rate limit hit - consider implementing backoff', {
54
- method: methodName,
55
- suggestion: 'Implement exponential backoff or request queuing',
56
- });
57
- }
58
- else if (error.message?.includes('network')) {
59
- logger.warn('Network error - check connectivity', {
60
- method: methodName,
61
- suggestion: 'Verify API endpoint and network connectivity',
62
- });
63
- }
64
- else if (error.message?.includes('unauthorized')) {
65
- logger.warn('Authorization error - check API key', {
66
- method: methodName,
67
- suggestion: 'Verify LINEAR_API_KEY is set and valid',
68
- });
69
- }
70
- throw error;
71
- }
72
- });
73
- };
74
- }
75
- else {
76
- descriptor.value = function (...args) {
77
- const className = target.constructor.name;
78
- const methodName = `${className}.${propertyKey}`;
79
- const context = extractAPIContext(propertyKey, args);
80
- return trace.traceSync('api', methodName, context, () => {
81
- return originalMethod.apply(this, args);
82
- });
83
- };
84
- }
85
- return descriptor;
86
- }
87
- /**
88
- * Extract meaningful context from API method arguments
89
- */
90
- function extractAPIContext(methodName, args) {
91
- const context = {};
92
- // Handle different Linear API methods
93
- if (methodName === 'createIssue' && args[0]) {
94
- context.title = args[0].title;
95
- context.teamId = args[0].teamId;
96
- context.priority = args[0].priority;
97
- }
98
- else if (methodName === 'updateIssue' && args[0]) {
99
- context.issueId = args[0];
100
- context.updates = Object.keys(args[1] || {});
101
- }
102
- else if (methodName === 'getIssue') {
103
- context.issueId = args[0];
104
- }
105
- else if (methodName === 'getIssues' && args[0]) {
106
- context.filter = args[0];
107
- }
108
- else if (methodName === 'graphql') {
109
- // For raw GraphQL queries
110
- const query = args[0];
111
- if (query) {
112
- // Extract operation name from query
113
- const match = query.match(/(?:query|mutation)\s+(\w+)/);
114
- context.operation = match ? match[1] : 'unknown';
115
- context.queryLength = query.length;
116
- context.variables = args[1] ? Object.keys(args[1]) : [];
117
- }
118
- }
119
- return context;
120
- }
121
- /**
122
- * Wrap fetch with tracing for HTTP-level debugging
123
- */
124
- export function createTracedFetch(baseFetch = fetch) {
125
- return async function tracedFetch(input, init) {
126
- const url = typeof input === 'string' ? input : input.toString();
127
- const method = init?.method || 'GET';
128
- // Mask sensitive headers
129
- const headers = init?.headers ? { ...init.headers } : {};
130
- if (headers.Authorization) {
131
- headers.Authorization = headers.Authorization.substring(0, 20) + '...[MASKED]';
132
- }
133
- const context = {
134
- method,
135
- url: url.length > 100 ? url.substring(0, 100) + '...' : url,
136
- headers: Object.keys(headers),
137
- bodySize: init?.body ? JSON.stringify(init.body).length : 0,
138
- };
139
- return trace.api(method, url, context, async () => {
140
- const startTime = Date.now();
141
- try {
142
- const response = await baseFetch(input, init);
143
- const duration = Date.now() - startTime;
144
- // Log response details
145
- logger.debug(`HTTP ${method} ${response.status}`, {
146
- url: url.substring(0, 100),
147
- status: response.status,
148
- duration,
149
- headers: {
150
- 'content-type': response.headers.get('content-type'),
151
- 'x-ratelimit-remaining': response.headers.get('x-ratelimit-remaining'),
152
- 'x-ratelimit-reset': response.headers.get('x-ratelimit-reset'),
153
- },
154
- });
155
- // Warn about rate limiting
156
- const remaining = response.headers.get('x-ratelimit-remaining');
157
- if (remaining && parseInt(remaining) < 10) {
158
- logger.warn(`Low rate limit remaining: ${remaining}`, {
159
- url: url.substring(0, 100),
160
- resetAt: response.headers.get('x-ratelimit-reset'),
161
- });
162
- }
163
- // Warn about slow responses
164
- if (duration > 2000) {
165
- logger.warn(`Slow HTTP response: ${duration}ms`, {
166
- method,
167
- url: url.substring(0, 100),
168
- status: response.status,
169
- });
170
- }
171
- return response;
172
- }
173
- catch (error) {
174
- const duration = Date.now() - startTime;
175
- logger.error(`HTTP ${method} failed`, error, {
176
- url: url.substring(0, 100),
177
- duration,
178
- errorType: error.constructor.name,
179
- errno: error.errno,
180
- code: error.code,
181
- });
182
- throw error;
183
- }
184
- });
185
- };
186
- }
187
- /**
188
- * Create a traced GraphQL client wrapper
189
- */
190
- export function wrapGraphQLClient(client) {
191
- const prototype = Object.getPrototypeOf(client);
192
- const propertyNames = Object.getOwnPropertyNames(prototype);
193
- for (const propertyName of propertyNames) {
194
- if (propertyName === 'constructor')
195
- continue;
196
- const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);
197
- if (!descriptor || typeof descriptor.value !== 'function')
198
- continue;
199
- // Apply tracing to all methods
200
- TraceLinearAPI(prototype, propertyName, descriptor);
201
- Object.defineProperty(prototype, propertyName, descriptor);
202
- }
203
- return client;
204
- }