@glasstrace/sdk 0.4.0 → 0.4.2
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/{chunk-TJ6ETQPH.js → chunk-67H2JEI4.js} +11 -5
- package/dist/{chunk-TJ6ETQPH.js.map → chunk-67H2JEI4.js.map} +1 -1
- package/dist/{chunk-STECO33B.js → chunk-PLJVIWHN.js} +1 -1
- package/dist/chunk-PLJVIWHN.js.map +1 -0
- package/dist/{chunk-EC5IINUT.js → chunk-TVOYTJ7I.js} +17 -4
- package/dist/chunk-TVOYTJ7I.js.map +1 -0
- package/dist/cli/init.cjs +9 -3
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +3 -3
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +2 -2
- package/dist/index.cjs +102 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +77 -39
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EC5IINUT.js.map +0 -1
- package/dist/chunk-STECO33B.js.map +0 -1
package/dist/cli/mcp-add.js
CHANGED
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
scaffoldMcpMarker,
|
|
7
7
|
updateGitignore,
|
|
8
8
|
writeMcpConfig
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-PLJVIWHN.js";
|
|
10
10
|
import {
|
|
11
11
|
readAnonKey
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-TVOYTJ7I.js";
|
|
13
13
|
import "../chunk-PZ5AY32C.js";
|
|
14
14
|
|
|
15
15
|
// src/cli/mcp-add.ts
|
package/dist/index.cjs
CHANGED
|
@@ -15741,15 +15741,28 @@ async function getOrCreateAnonKey(projectRoot) {
|
|
|
15741
15741
|
const newKey = createAnonApiKey();
|
|
15742
15742
|
try {
|
|
15743
15743
|
await (0, import_promises.mkdir)(dirPath, { recursive: true, mode: 448 });
|
|
15744
|
-
await (0, import_promises.writeFile)(keyPath, newKey, "
|
|
15745
|
-
|
|
15744
|
+
await (0, import_promises.writeFile)(keyPath, newKey, { flag: "wx", mode: 384 });
|
|
15745
|
+
return newKey;
|
|
15746
15746
|
} catch (err) {
|
|
15747
|
+
const code = err.code;
|
|
15748
|
+
if (code === "EEXIST") {
|
|
15749
|
+
const winnerKey = await readAnonKey(root);
|
|
15750
|
+
if (winnerKey !== null) {
|
|
15751
|
+
return winnerKey;
|
|
15752
|
+
}
|
|
15753
|
+
try {
|
|
15754
|
+
await (0, import_promises.writeFile)(keyPath, newKey, { mode: 384 });
|
|
15755
|
+
await (0, import_promises.chmod)(keyPath, 384);
|
|
15756
|
+
return newKey;
|
|
15757
|
+
} catch {
|
|
15758
|
+
}
|
|
15759
|
+
}
|
|
15747
15760
|
ephemeralKeyCache.set(root, newKey);
|
|
15748
15761
|
console.warn(
|
|
15749
15762
|
`[glasstrace] Failed to persist anonymous key to ${keyPath}: ${err instanceof Error ? err.message : String(err)}. Using ephemeral key.`
|
|
15750
15763
|
);
|
|
15764
|
+
return newKey;
|
|
15751
15765
|
}
|
|
15752
|
-
return newKey;
|
|
15753
15766
|
}
|
|
15754
15767
|
|
|
15755
15768
|
// src/init-client.ts
|
|
@@ -16023,9 +16036,13 @@ var GlasstraceExporter = class {
|
|
|
16023
16036
|
* Enriches a ReadableSpan with all glasstrace.* attributes.
|
|
16024
16037
|
* Returns a new ReadableSpan wrapper; the original span is not mutated.
|
|
16025
16038
|
*
|
|
16026
|
-
*
|
|
16027
|
-
*
|
|
16028
|
-
*
|
|
16039
|
+
* Only {@link SessionManager.getSessionId} is individually guarded because
|
|
16040
|
+
* it calls into crypto and schema validation — a session ID failure should
|
|
16041
|
+
* not prevent the rest of enrichment. The other helper calls
|
|
16042
|
+
* ({@link deriveErrorCategory}, {@link deriveOrmProvider},
|
|
16043
|
+
* {@link classifyFetchTarget}) are pure functions on typed string inputs
|
|
16044
|
+
* and rely on the outer catch for any unexpected failure.
|
|
16045
|
+
*
|
|
16029
16046
|
* On total failure, returns the original span unchanged.
|
|
16030
16047
|
*/
|
|
16031
16048
|
enrichSpan(span) {
|
|
@@ -16068,44 +16085,39 @@ var GlasstraceExporter = class {
|
|
|
16068
16085
|
}
|
|
16069
16086
|
}
|
|
16070
16087
|
const errorMessage = attrs["exception.message"];
|
|
16071
|
-
if (errorMessage) {
|
|
16088
|
+
if (typeof errorMessage === "string") {
|
|
16072
16089
|
extra[ATTR.ERROR_MESSAGE] = errorMessage;
|
|
16073
16090
|
}
|
|
16074
|
-
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
|
|
16079
|
-
}
|
|
16080
|
-
} catch {
|
|
16091
|
+
const errorType = attrs["exception.type"];
|
|
16092
|
+
if (typeof errorType === "string") {
|
|
16093
|
+
extra[ATTR.ERROR_CODE] = errorType;
|
|
16094
|
+
extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
|
|
16081
16095
|
}
|
|
16082
16096
|
const errorField = attrs["error.field"];
|
|
16083
|
-
if (errorField) {
|
|
16097
|
+
if (typeof errorField === "string") {
|
|
16084
16098
|
extra[ATTR.ERROR_FIELD] = errorField;
|
|
16085
16099
|
}
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
const operation = attrs["db.operation"];
|
|
16097
|
-
if (operation) {
|
|
16098
|
-
extra[ATTR.ORM_OPERATION] = operation;
|
|
16099
|
-
}
|
|
16100
|
+
const spanAny = span;
|
|
16101
|
+
const instrumentationName = spanAny.instrumentationScope?.name ?? spanAny.instrumentationLibrary?.name ?? "";
|
|
16102
|
+
const ormProvider = deriveOrmProvider(instrumentationName);
|
|
16103
|
+
if (ormProvider) {
|
|
16104
|
+
extra[ATTR.ORM_PROVIDER] = ormProvider;
|
|
16105
|
+
const table = attrs["db.sql.table"];
|
|
16106
|
+
const prismaModel = attrs["db.prisma.model"];
|
|
16107
|
+
const model = typeof table === "string" ? table : typeof prismaModel === "string" ? prismaModel : void 0;
|
|
16108
|
+
if (model) {
|
|
16109
|
+
extra[ATTR.ORM_MODEL] = model;
|
|
16100
16110
|
}
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
const url2 = attrs["http.url"] ?? attrs["url.full"];
|
|
16105
|
-
if (url2 && span.kind === SpanKind.CLIENT) {
|
|
16106
|
-
extra[ATTR.FETCH_TARGET] = classifyFetchTarget(url2);
|
|
16111
|
+
const operation = attrs["db.operation"];
|
|
16112
|
+
if (typeof operation === "string") {
|
|
16113
|
+
extra[ATTR.ORM_OPERATION] = operation;
|
|
16107
16114
|
}
|
|
16108
|
-
}
|
|
16115
|
+
}
|
|
16116
|
+
const httpUrl2 = attrs["http.url"];
|
|
16117
|
+
const fullUrl = attrs["url.full"];
|
|
16118
|
+
const url2 = typeof httpUrl2 === "string" ? httpUrl2 : typeof fullUrl === "string" ? fullUrl : void 0;
|
|
16119
|
+
if (url2 && span.kind === SpanKind.CLIENT) {
|
|
16120
|
+
extra[ATTR.FETCH_TARGET] = classifyFetchTarget(url2);
|
|
16109
16121
|
}
|
|
16110
16122
|
return createEnrichedSpan(span, extra);
|
|
16111
16123
|
} catch {
|
|
@@ -19143,7 +19155,7 @@ function registerGlasstrace(options) {
|
|
|
19143
19155
|
if (config2.verbose) {
|
|
19144
19156
|
console.info("[glasstrace] Background init firing.");
|
|
19145
19157
|
}
|
|
19146
|
-
await performInit(config2, anonKey, "0.4.
|
|
19158
|
+
await performInit(config2, anonKey, "0.4.2");
|
|
19147
19159
|
maybeInstallConsoleCapture();
|
|
19148
19160
|
} catch (err) {
|
|
19149
19161
|
console.warn(
|
|
@@ -19163,7 +19175,7 @@ function registerGlasstrace(options) {
|
|
|
19163
19175
|
if (config2.verbose) {
|
|
19164
19176
|
console.info("[glasstrace] Background init firing.");
|
|
19165
19177
|
}
|
|
19166
|
-
await performInit(config2, anonKey, "0.4.
|
|
19178
|
+
await performInit(config2, anonKey, "0.4.2");
|
|
19167
19179
|
maybeInstallConsoleCapture();
|
|
19168
19180
|
} catch (err) {
|
|
19169
19181
|
console.warn(
|
|
@@ -19185,7 +19197,7 @@ function registerGlasstrace(options) {
|
|
|
19185
19197
|
if (config2.verbose) {
|
|
19186
19198
|
console.info("[glasstrace] Background init firing.");
|
|
19187
19199
|
}
|
|
19188
|
-
await performInit(config2, anonKeyForInit, "0.4.
|
|
19200
|
+
await performInit(config2, anonKeyForInit, "0.4.2");
|
|
19189
19201
|
maybeInstallConsoleCapture();
|
|
19190
19202
|
} catch (err) {
|
|
19191
19203
|
console.warn(
|
|
@@ -19284,7 +19296,10 @@ async function uploadSourceMaps(apiKey, endpoint, buildHash, maps) {
|
|
|
19284
19296
|
sourceMap: m.content
|
|
19285
19297
|
}))
|
|
19286
19298
|
};
|
|
19287
|
-
|
|
19299
|
+
let baseUrl = endpoint;
|
|
19300
|
+
while (baseUrl.endsWith("/")) {
|
|
19301
|
+
baseUrl = baseUrl.slice(0, -1);
|
|
19302
|
+
}
|
|
19288
19303
|
const response = await fetch(`${baseUrl}/v1/source-maps`, {
|
|
19289
19304
|
method: "POST",
|
|
19290
19305
|
headers: {
|
|
@@ -19370,6 +19385,43 @@ async function handleSourceMapUpload(distDir) {
|
|
|
19370
19385
|
|
|
19371
19386
|
// src/capture-error.ts
|
|
19372
19387
|
init_esm();
|
|
19388
|
+
|
|
19389
|
+
// src/nudge/error-nudge.ts
|
|
19390
|
+
var import_node_fs2 = require("fs");
|
|
19391
|
+
var import_node_path3 = require("path");
|
|
19392
|
+
var hasFired = false;
|
|
19393
|
+
function sanitize(input) {
|
|
19394
|
+
return input.replace(/[\x00-\x1f\x7f]/g, "");
|
|
19395
|
+
}
|
|
19396
|
+
function maybeShowMcpNudge(errorSummary) {
|
|
19397
|
+
if (hasFired) {
|
|
19398
|
+
return;
|
|
19399
|
+
}
|
|
19400
|
+
const config2 = resolveConfig();
|
|
19401
|
+
if (isProductionDisabled(config2)) {
|
|
19402
|
+
return;
|
|
19403
|
+
}
|
|
19404
|
+
let markerExists = false;
|
|
19405
|
+
try {
|
|
19406
|
+
const markerPath = (0, import_node_path3.join)(process.cwd(), ".glasstrace", "mcp-connected");
|
|
19407
|
+
markerExists = (0, import_node_fs2.existsSync)(markerPath);
|
|
19408
|
+
} catch {
|
|
19409
|
+
markerExists = false;
|
|
19410
|
+
}
|
|
19411
|
+
if (markerExists) {
|
|
19412
|
+
return;
|
|
19413
|
+
}
|
|
19414
|
+
hasFired = true;
|
|
19415
|
+
const safe = sanitize(errorSummary);
|
|
19416
|
+
process.stderr.write(
|
|
19417
|
+
`[glasstrace] Error captured: ${safe}
|
|
19418
|
+
Debug with AI: ask your agent "What's the latest Glasstrace error?"
|
|
19419
|
+
Not connected? Run: npx glasstrace mcp add
|
|
19420
|
+
`
|
|
19421
|
+
);
|
|
19422
|
+
}
|
|
19423
|
+
|
|
19424
|
+
// src/capture-error.ts
|
|
19373
19425
|
function captureError(error48) {
|
|
19374
19426
|
try {
|
|
19375
19427
|
const span = trace.getSpan(context.active());
|
|
@@ -19381,6 +19433,7 @@ function captureError(error48) {
|
|
|
19381
19433
|
attributes["error.type"] = error48.constructor.name;
|
|
19382
19434
|
}
|
|
19383
19435
|
span.addEvent("glasstrace.error", attributes);
|
|
19436
|
+
maybeShowMcpNudge(String(error48));
|
|
19384
19437
|
} catch {
|
|
19385
19438
|
}
|
|
19386
19439
|
}
|
|
@@ -19506,12 +19559,18 @@ function extractImports(fileContent) {
|
|
|
19506
19559
|
imports.push(importPath);
|
|
19507
19560
|
}
|
|
19508
19561
|
};
|
|
19509
|
-
const
|
|
19562
|
+
const esFromImportRegex = /\bimport\b[^'"]+\bfrom\s+['"]([^'"]+)['"]/g;
|
|
19563
|
+
const esSideEffectRegex = /\bimport\s+['"]([^'"]+)['"]/g;
|
|
19510
19564
|
let match;
|
|
19511
|
-
match =
|
|
19565
|
+
match = esFromImportRegex.exec(fileContent);
|
|
19566
|
+
while (match !== null) {
|
|
19567
|
+
addUnique(match[1]);
|
|
19568
|
+
match = esFromImportRegex.exec(fileContent);
|
|
19569
|
+
}
|
|
19570
|
+
match = esSideEffectRegex.exec(fileContent);
|
|
19512
19571
|
while (match !== null) {
|
|
19513
19572
|
addUnique(match[1]);
|
|
19514
|
-
match =
|
|
19573
|
+
match = esSideEffectRegex.exec(fileContent);
|
|
19515
19574
|
}
|
|
19516
19575
|
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
19517
19576
|
match = requireRegex.exec(fileContent);
|