trickle-observe 0.2.89 → 0.2.90
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/dist/trace-var.js +57 -0
- package/package.json +1 -1
- package/src/trace-var.ts +57 -0
package/dist/trace-var.js
CHANGED
|
@@ -238,4 +238,61 @@ if (typeof process !== 'undefined' && process.on) {
|
|
|
238
238
|
process.on('beforeExit', exitFlush);
|
|
239
239
|
process.on('SIGTERM', exitFlush);
|
|
240
240
|
process.on('SIGINT', exitFlush);
|
|
241
|
+
// Capture uncaught exceptions with variable context for agent debugging.
|
|
242
|
+
// Write error + nearby variable values to errors.jsonl before the process exits.
|
|
243
|
+
process.on('uncaughtException', (err) => {
|
|
244
|
+
flushVarBuffer();
|
|
245
|
+
try {
|
|
246
|
+
const dir = varsFilePath
|
|
247
|
+
? path.dirname(varsFilePath)
|
|
248
|
+
: process.env.TRICKLE_LOCAL_DIR || path.join(process.cwd(), '.trickle');
|
|
249
|
+
try {
|
|
250
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
251
|
+
}
|
|
252
|
+
catch { }
|
|
253
|
+
const errorsFile = path.join(dir, 'errors.jsonl');
|
|
254
|
+
// Extract file and line from stack trace
|
|
255
|
+
const stackLines = (err.stack || '').split('\n');
|
|
256
|
+
let errorFile;
|
|
257
|
+
let errorLine;
|
|
258
|
+
for (const sl of stackLines.slice(1)) {
|
|
259
|
+
const m = sl.match(/\((.+):(\d+):\d+\)/) || sl.match(/at (.+):(\d+):\d+/);
|
|
260
|
+
if (m && !m[1].includes('node_modules') && !m[1].includes('node:') && !m[1].includes('trickle')) {
|
|
261
|
+
errorFile = m[1];
|
|
262
|
+
errorLine = parseInt(m[2]);
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Find nearby variable values from the cache
|
|
267
|
+
const nearbyVars = {};
|
|
268
|
+
if (errorFile && errorLine) {
|
|
269
|
+
for (const [key, entry] of varCache) {
|
|
270
|
+
const parts = key.split(':');
|
|
271
|
+
const file = parts[0];
|
|
272
|
+
const line = parseInt(parts[1]);
|
|
273
|
+
const varName = parts.slice(2).join(':');
|
|
274
|
+
if (file === errorFile && Math.abs(line - errorLine) <= 10) {
|
|
275
|
+
nearbyVars[`L${parts[1]} ${varName}`] = entry.fp;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const record = {
|
|
280
|
+
kind: 'error',
|
|
281
|
+
error: err.message,
|
|
282
|
+
type: err.constructor.name,
|
|
283
|
+
file: errorFile,
|
|
284
|
+
line: errorLine,
|
|
285
|
+
stack: stackLines.slice(0, 6).join('\n'),
|
|
286
|
+
nearbyVariables: Object.keys(nearbyVars).length > 0 ? nearbyVars : undefined,
|
|
287
|
+
timestamp: new Date().toISOString(),
|
|
288
|
+
};
|
|
289
|
+
fs.appendFileSync(errorsFile, JSON.stringify(record) + '\n');
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
// Never suppress the original error
|
|
293
|
+
}
|
|
294
|
+
// Print the original error and exit (don't re-throw to preserve original stack)
|
|
295
|
+
console.error(err.stack || err.message);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
});
|
|
241
298
|
}
|
package/package.json
CHANGED
package/src/trace-var.ts
CHANGED
|
@@ -221,4 +221,61 @@ if (typeof process !== 'undefined' && process.on) {
|
|
|
221
221
|
process.on('beforeExit', exitFlush);
|
|
222
222
|
process.on('SIGTERM', exitFlush);
|
|
223
223
|
process.on('SIGINT', exitFlush);
|
|
224
|
+
|
|
225
|
+
// Capture uncaught exceptions with variable context for agent debugging.
|
|
226
|
+
// Write error + nearby variable values to errors.jsonl before the process exits.
|
|
227
|
+
process.on('uncaughtException', (err: Error) => {
|
|
228
|
+
flushVarBuffer();
|
|
229
|
+
try {
|
|
230
|
+
const dir = varsFilePath
|
|
231
|
+
? path.dirname(varsFilePath)
|
|
232
|
+
: process.env.TRICKLE_LOCAL_DIR || path.join(process.cwd(), '.trickle');
|
|
233
|
+
try { fs.mkdirSync(dir, { recursive: true }); } catch {}
|
|
234
|
+
const errorsFile = path.join(dir, 'errors.jsonl');
|
|
235
|
+
|
|
236
|
+
// Extract file and line from stack trace
|
|
237
|
+
const stackLines = (err.stack || '').split('\n');
|
|
238
|
+
let errorFile: string | undefined;
|
|
239
|
+
let errorLine: number | undefined;
|
|
240
|
+
for (const sl of stackLines.slice(1)) {
|
|
241
|
+
const m = sl.match(/\((.+):(\d+):\d+\)/) || sl.match(/at (.+):(\d+):\d+/);
|
|
242
|
+
if (m && !m[1].includes('node_modules') && !m[1].includes('node:') && !m[1].includes('trickle')) {
|
|
243
|
+
errorFile = m[1];
|
|
244
|
+
errorLine = parseInt(m[2]);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Find nearby variable values from the cache
|
|
250
|
+
const nearbyVars: Record<string, string> = {};
|
|
251
|
+
if (errorFile && errorLine) {
|
|
252
|
+
for (const [key, entry] of varCache) {
|
|
253
|
+
const parts = key.split(':');
|
|
254
|
+
const file = parts[0];
|
|
255
|
+
const line = parseInt(parts[1]);
|
|
256
|
+
const varName = parts.slice(2).join(':');
|
|
257
|
+
if (file === errorFile && Math.abs(line - errorLine) <= 10) {
|
|
258
|
+
nearbyVars[`L${parts[1]} ${varName}`] = entry.fp;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const record = {
|
|
264
|
+
kind: 'error',
|
|
265
|
+
error: err.message,
|
|
266
|
+
type: err.constructor.name,
|
|
267
|
+
file: errorFile,
|
|
268
|
+
line: errorLine,
|
|
269
|
+
stack: stackLines.slice(0, 6).join('\n'),
|
|
270
|
+
nearbyVariables: Object.keys(nearbyVars).length > 0 ? nearbyVars : undefined,
|
|
271
|
+
timestamp: new Date().toISOString(),
|
|
272
|
+
};
|
|
273
|
+
fs.appendFileSync(errorsFile, JSON.stringify(record) + '\n');
|
|
274
|
+
} catch {
|
|
275
|
+
// Never suppress the original error
|
|
276
|
+
}
|
|
277
|
+
// Print the original error and exit (don't re-throw to preserve original stack)
|
|
278
|
+
console.error(err.stack || err.message);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
});
|
|
224
281
|
}
|