Enhances code extraction and project indexing

Adds support for Dart and Liquid languages with tree-sitter parsing.
Improves accuracy of code symbol extraction for existing languages.
Indexes project files to enhance code navigation features.
Migrates build system to facilitate code contributions.
Removes git hook functionality.
Integrates Sentry for error tracking and reporting.
Enhances project initialization and configuration loading.
This commit is contained in:
Colby McHenry
2026-02-09 22:18:59 -06:00
parent f0ddfccf47
commit d0ee6f7fc4
50 changed files with 3428 additions and 3332 deletions
+167
View File
@@ -0,0 +1,167 @@
/**
* Lightweight Sentry client for CodeGraph — uses the HTTP envelope API directly.
* No @sentry/node dependency, works in any Node.js environment.
*/
import { createHash } from 'crypto';
const DSN = 'https://9591f8aca69bcf98e9feb31544200b47@o1181972.ingest.us.sentry.io/4510840133713920';
const DSN_PARTS = DSN.match(/^https:\/\/([^@]+)@([^/]+)\/(.+)$/);
const PUBLIC_KEY = DSN_PARTS![1];
const HOST = DSN_PARTS![2];
const PROJECT_ID = DSN_PARTS![3];
const STORE_URL = `https://${HOST}/api/${PROJECT_ID}/envelope/`;
let _enabled = false;
let _release = 'codegraph@unknown';
let _tags: Record<string, string> = {};
/**
* Initialize Sentry error reporting.
* Safe to call multiple times — subsequent calls update tags/release.
*/
export function initSentry({ processName, version }: { processName: string; version?: string }) {
// Skip in development/test environments
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' || process.env.VITEST) {
return;
}
_enabled = true;
_release = `codegraph@${version ?? process.env.npm_package_version ?? 'unknown'}`;
_tags = { processName };
}
/**
* Send an error to Sentry with full stack trace and context.
* Fire-and-forget — never throws, never blocks.
*/
export function captureException(error: unknown, extra?: Record<string, unknown>) {
if (!_enabled) return;
try {
const err = error instanceof Error ? error : new Error(String(error));
const msg = err.message.toLowerCase();
// Filter non-actionable noise
if (msg.includes('pty') || msg.includes('terminal session')) return;
if ((msg.includes('econnrefused') || msg.includes('econnreset')) && msg.includes('127.0.0.1')) return;
const eventId = createHash('md5').update(`${Date.now()}-${Math.random()}`).digest('hex');
const timestamp = new Date().toISOString();
// Attach CodeGraphError context if available
const errorContext: Record<string, unknown> = { ...extra };
if ('code' in err && typeof (err as any).code === 'string') {
errorContext.errorCode = (err as any).code;
}
if ('context' in err && typeof (err as any).context === 'object') {
Object.assign(errorContext, (err as any).context);
}
const event: Record<string, unknown> = {
event_id: eventId,
timestamp,
platform: 'node',
level: 'error',
release: _release,
tags: _tags,
exception: {
values: [{
type: err.name,
value: err.message,
stacktrace: parseStack(err.stack),
}],
},
};
if (Object.keys(errorContext).length > 0) {
event.extra = errorContext;
}
const payload = JSON.stringify(event);
const envelope = [
JSON.stringify({ event_id: eventId, sent_at: timestamp, dsn: DSN }),
JSON.stringify({ type: 'event', length: payload.length }),
payload,
].join('\n') + '\n';
fetch(STORE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-sentry-envelope',
'X-Sentry-Auth': `Sentry sentry_version=7, sentry_key=${PUBLIC_KEY}`,
},
body: envelope,
}).catch(() => {});
} catch {
// Never throw from error reporting
}
}
/**
* Send a message-level event to Sentry (for logged errors without Error objects).
*/
export function captureMessage(message: string, context?: Record<string, unknown>) {
if (!_enabled) return;
try {
const eventId = createHash('md5').update(`${Date.now()}-${Math.random()}`).digest('hex');
const timestamp = new Date().toISOString();
const event: Record<string, unknown> = {
event_id: eventId,
timestamp,
platform: 'node',
level: 'error',
release: _release,
tags: _tags,
message: { formatted: message },
};
if (context && Object.keys(context).length > 0) {
event.extra = context;
}
const payload = JSON.stringify(event);
const envelope = [
JSON.stringify({ event_id: eventId, sent_at: timestamp, dsn: DSN }),
JSON.stringify({ type: 'event', length: payload.length }),
payload,
].join('\n') + '\n';
fetch(STORE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-sentry-envelope',
'X-Sentry-Auth': `Sentry sentry_version=7, sentry_key=${PUBLIC_KEY}`,
},
body: envelope,
}).catch(() => {});
} catch {
// Never throw from error reporting
}
}
/**
* Parse a Node.js Error.stack string into Sentry's stacktrace format.
*/
function parseStack(stack?: string): { frames: Array<{ filename: string; function: string; lineno?: number; colno?: number }> } | undefined {
if (!stack) return undefined;
const frames = stack
.split('\n')
.slice(1)
.map((line) => {
const match = line.match(/^\s+at\s+(?:(.+?)\s+\()?(.*?):(\d+):(\d+)\)?$/);
if (!match || !match[2] || !match[3] || !match[4]) return null;
return {
function: match[1] || '<anonymous>',
filename: match[2],
lineno: parseInt(match[3], 10),
colno: parseInt(match[4], 10),
};
})
.filter((f): f is NonNullable<typeof f> => f !== null)
.reverse();
return frames.length > 0 ? { frames } : undefined;
}