@glasstrace/sdk 1.1.1 → 1.1.3

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 (49) hide show
  1. package/README.md +78 -1
  2. package/dist/{chunk-DIM4JRXM.js → chunk-2M57EO6U.js} +2 -2
  3. package/dist/{chunk-Y26HJUPD.js → chunk-FGDS33I2.js} +138 -12
  4. package/dist/chunk-FGDS33I2.js.map +1 -0
  5. package/dist/{chunk-MXDZHFJQ.js → chunk-JKI4OCFV.js} +4 -14
  6. package/dist/chunk-JKI4OCFV.js.map +1 -0
  7. package/dist/{chunk-7SZQN6IU.js → chunk-NB7GJE4S.js} +2 -2
  8. package/dist/chunk-NB7GJE4S.js.map +1 -0
  9. package/dist/{chunk-ZRDQ6ZKI.js → chunk-TWHCJKRS.js} +101 -481
  10. package/dist/chunk-TWHCJKRS.js.map +1 -0
  11. package/dist/{chunk-P22UQ2OJ.js → chunk-TWTWRJ25.js} +233 -9
  12. package/dist/chunk-TWTWRJ25.js.map +1 -0
  13. package/dist/cli/init.cjs +2494 -2332
  14. package/dist/cli/init.cjs.map +1 -1
  15. package/dist/cli/init.js +434 -63
  16. package/dist/cli/init.js.map +1 -1
  17. package/dist/cli/mcp-add.cjs +14 -2
  18. package/dist/cli/mcp-add.cjs.map +1 -1
  19. package/dist/cli/mcp-add.js +17 -5
  20. package/dist/cli/mcp-add.js.map +1 -1
  21. package/dist/cli/status.cjs.map +1 -1
  22. package/dist/cli/status.js +1 -3
  23. package/dist/cli/status.js.map +1 -1
  24. package/dist/cli/uninit.cjs +116 -14
  25. package/dist/cli/uninit.cjs.map +1 -1
  26. package/dist/cli/uninit.js +3 -3
  27. package/dist/cli/validate.cjs +14162 -2
  28. package/dist/cli/validate.cjs.map +1 -1
  29. package/dist/cli/validate.d.cts +7 -3
  30. package/dist/cli/validate.d.ts +7 -3
  31. package/dist/cli/validate.js +25 -2
  32. package/dist/cli/validate.js.map +1 -1
  33. package/dist/index.cjs +339 -28
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +12 -9
  36. package/dist/index.d.ts +12 -9
  37. package/dist/index.js +3 -3
  38. package/dist/{monorepo-GSL6JD3G.js → monorepo-PFVNPQ6X.js} +3 -5
  39. package/dist/node-entry.cjs +339 -28
  40. package/dist/node-entry.cjs.map +1 -1
  41. package/dist/node-entry.js +3 -3
  42. package/package.json +1 -1
  43. package/dist/chunk-7SZQN6IU.js.map +0 -1
  44. package/dist/chunk-MXDZHFJQ.js.map +0 -1
  45. package/dist/chunk-P22UQ2OJ.js.map +0 -1
  46. package/dist/chunk-Y26HJUPD.js.map +0 -1
  47. package/dist/chunk-ZRDQ6ZKI.js.map +0 -1
  48. /package/dist/{chunk-DIM4JRXM.js.map → chunk-2M57EO6U.js.map} +0 -0
  49. /package/dist/{monorepo-GSL6JD3G.js.map → monorepo-PFVNPQ6X.js.map} +0 -0
package/dist/cli/init.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveProjectRoot
4
- } from "../chunk-DIM4JRXM.js";
4
+ } from "../chunk-2M57EO6U.js";
5
5
  import {
6
6
  verifyInitReachable
7
- } from "../chunk-MXDZHFJQ.js";
7
+ } from "../chunk-JKI4OCFV.js";
8
8
  import {
9
9
  buildImportGraph
10
10
  } from "../chunk-DST4UBXU.js";
@@ -12,22 +12,16 @@ import {
12
12
  resolveConfig
13
13
  } from "../chunk-VUZCLMIX.js";
14
14
  import {
15
- addCoverageMapEnv,
16
15
  isInitCreatedInstrumentation,
17
16
  relativeDiscoveryPath,
18
17
  removeDiscoveryFile,
19
18
  removeGlasstraceConfigImport,
20
19
  removeRegisterGlasstrace,
21
- resolveInstrumentationTarget,
22
20
  resolveStaticRoot,
23
- scaffoldEnvLocal,
24
- scaffoldGitignore,
25
- scaffoldInstrumentation,
26
- scaffoldNextConfig,
27
21
  unwrapCJSExport,
28
22
  unwrapExport,
29
23
  writeDiscoveryFile
30
- } from "../chunk-ZRDQ6ZKI.js";
24
+ } from "../chunk-TWHCJKRS.js";
31
25
  import {
32
26
  detectAgents,
33
27
  generateInfoSection,
@@ -36,10 +30,6 @@ import {
36
30
  updateGitignore,
37
31
  writeMcpConfig
38
32
  } from "../chunk-P4OYPFQ5.js";
39
- import {
40
- NEXT_CONFIG_NAMES,
41
- formatAgentName
42
- } from "../chunk-7SZQN6IU.js";
43
33
  import {
44
34
  MCP_ENDPOINT,
45
35
  getOrCreateAnonKey,
@@ -50,14 +40,395 @@ import {
50
40
  readEnvLocalApiKey,
51
41
  resolveEffectiveMcpCredential,
52
42
  writeMcpMarker
53
- } from "../chunk-P22UQ2OJ.js";
43
+ } from "../chunk-TWTWRJ25.js";
54
44
  import "../chunk-X5MAXP5T.js";
45
+ import {
46
+ NEXT_CONFIG_NAMES,
47
+ formatAgentName
48
+ } from "../chunk-NB7GJE4S.js";
55
49
  import "../chunk-NSBPE2FW.js";
56
50
 
57
51
  // src/cli/init.ts
52
+ import * as fs2 from "node:fs";
53
+ import * as path2 from "node:path";
54
+ import * as readline from "node:readline";
55
+
56
+ // src/cli/scaffolder.ts
58
57
  import * as fs from "node:fs";
59
58
  import * as path from "node:path";
60
- import * as readline from "node:readline";
59
+ function hasRegisterGlasstraceCall(content) {
60
+ return content.split("\n").some((line) => {
61
+ const uncommented = line.replace(/\/\/.*$/, "");
62
+ return /\bregisterGlasstrace\s*\(/.test(uncommented);
63
+ });
64
+ }
65
+ function injectRegisterGlasstrace(content) {
66
+ if (hasRegisterGlasstraceCall(content)) {
67
+ return { injected: false, content };
68
+ }
69
+ const registerFnRegex = /export\s+(?:async\s+)?function\s+register\s*\([^)]*\)\s*\{/;
70
+ const match = registerFnRegex.exec(content);
71
+ if (!match) {
72
+ return { injected: false, content };
73
+ }
74
+ const afterBrace = content.slice(match.index + match[0].length);
75
+ const indentMatch = /\n([ \t]+)/.exec(afterBrace);
76
+ const indent = indentMatch ? indentMatch[1] : " ";
77
+ const importLine = 'import { registerGlasstrace } from "@glasstrace/sdk";\n';
78
+ const hasGlasstraceImport = content.includes("@glasstrace/sdk");
79
+ const insertPoint = match.index + match[0].length;
80
+ const callInjection = `
81
+ ${indent}// Glasstrace must be registered before other instrumentation
82
+ ${indent}registerGlasstrace();
83
+ `;
84
+ let modified;
85
+ if (hasGlasstraceImport) {
86
+ const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']@glasstrace\/sdk["']/;
87
+ const importMatch = importRegex.exec(content);
88
+ if (importMatch) {
89
+ const specifiers = importMatch[1];
90
+ const alreadyImported = specifiers.split(",").some((s) => s.trim() === "registerGlasstrace");
91
+ if (alreadyImported) {
92
+ modified = content.slice(0, insertPoint) + callInjection + content.slice(insertPoint);
93
+ } else {
94
+ const existingImports = specifiers.trimEnd();
95
+ const separator = existingImports.endsWith(",") ? " " : ", ";
96
+ const updatedImport = `import { ${existingImports.trim()}${separator}registerGlasstrace } from "@glasstrace/sdk"`;
97
+ modified = content.replace(importMatch[0], updatedImport);
98
+ const newMatch = registerFnRegex.exec(modified);
99
+ if (newMatch) {
100
+ const newInsertPoint = newMatch.index + newMatch[0].length;
101
+ modified = modified.slice(0, newInsertPoint) + callInjection + modified.slice(newInsertPoint);
102
+ }
103
+ }
104
+ } else {
105
+ modified = importLine + content;
106
+ const newMatch = registerFnRegex.exec(modified);
107
+ if (newMatch) {
108
+ const newInsertPoint = newMatch.index + newMatch[0].length;
109
+ modified = modified.slice(0, newInsertPoint) + callInjection + modified.slice(newInsertPoint);
110
+ }
111
+ }
112
+ } else {
113
+ modified = importLine + content.slice(0, insertPoint) + callInjection + content.slice(insertPoint);
114
+ }
115
+ return { injected: true, content: modified };
116
+ }
117
+ var INSTRUMENTATION_FILENAMES = [
118
+ "instrumentation.ts",
119
+ "instrumentation.js",
120
+ "instrumentation.mjs"
121
+ ];
122
+ function resolveInstrumentationTarget(projectRoot) {
123
+ const rootExisting = [];
124
+ const srcExisting = [];
125
+ for (const name of INSTRUMENTATION_FILENAMES) {
126
+ const rootPath = path.join(projectRoot, name);
127
+ if (isRegularFile(rootPath)) {
128
+ rootExisting.push(rootPath);
129
+ }
130
+ const srcPath = path.join(projectRoot, "src", name);
131
+ if (isRegularFile(srcPath)) {
132
+ srcExisting.push(srcPath);
133
+ }
134
+ }
135
+ const existing = [...rootExisting, ...srcExisting];
136
+ if (rootExisting.length > 0 && srcExisting.length > 0) {
137
+ return {
138
+ target: null,
139
+ layout: null,
140
+ existing,
141
+ rootExisting,
142
+ srcExisting,
143
+ conflict: true
144
+ };
145
+ }
146
+ if (srcExisting.length > 0) {
147
+ return {
148
+ target: srcExisting[0],
149
+ layout: "src",
150
+ existing,
151
+ rootExisting,
152
+ srcExisting,
153
+ conflict: false
154
+ };
155
+ }
156
+ if (rootExisting.length > 0) {
157
+ return {
158
+ target: rootExisting[0],
159
+ layout: "root",
160
+ existing,
161
+ rootExisting,
162
+ srcExisting,
163
+ conflict: false
164
+ };
165
+ }
166
+ const srcDir = path.join(projectRoot, "src");
167
+ const layout = isDirectory(srcDir) ? "src" : "root";
168
+ const target = layout === "src" ? path.join(projectRoot, "src", "instrumentation.ts") : path.join(projectRoot, "instrumentation.ts");
169
+ return {
170
+ target,
171
+ layout,
172
+ existing,
173
+ rootExisting,
174
+ srcExisting,
175
+ conflict: false
176
+ };
177
+ }
178
+ function isDirectory(p) {
179
+ try {
180
+ return fs.statSync(p).isDirectory();
181
+ } catch {
182
+ return false;
183
+ }
184
+ }
185
+ function isRegularFile(p) {
186
+ try {
187
+ const stat = fs.lstatSync(p);
188
+ if (stat.isSymbolicLink()) {
189
+ return fs.statSync(p).isFile();
190
+ }
191
+ return stat.isFile();
192
+ } catch {
193
+ return false;
194
+ }
195
+ }
196
+ function appendRegisterFunction(content) {
197
+ const importLine = 'import { registerGlasstrace } from "@glasstrace/sdk";\n';
198
+ const functionBlock = "\nexport async function register() {\n // Glasstrace must be registered before Prisma instrumentation\n // to ensure all ORM spans are captured correctly.\n // If you use @prisma/instrumentation, import it after this call.\n registerGlasstrace();\n}\n";
199
+ let withImport = content;
200
+ const hasGlasstraceImport = content.includes("@glasstrace/sdk");
201
+ if (!hasGlasstraceImport) {
202
+ withImport = importLine + content;
203
+ } else {
204
+ const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']@glasstrace\/sdk["']/;
205
+ const importMatch = importRegex.exec(content);
206
+ if (importMatch) {
207
+ const specifiers = importMatch[1];
208
+ const alreadyImported = specifiers.split(",").some((s) => s.trim() === "registerGlasstrace");
209
+ if (!alreadyImported) {
210
+ const existingImports = specifiers.trimEnd();
211
+ const separator = existingImports.endsWith(",") ? " " : ", ";
212
+ const updatedImport = `import { ${existingImports.trim()}${separator}registerGlasstrace } from "@glasstrace/sdk"`;
213
+ withImport = content.replace(importMatch[0], updatedImport);
214
+ }
215
+ } else {
216
+ withImport = importLine + content;
217
+ }
218
+ }
219
+ const trailingNewline = withImport.endsWith("\n") ? "" : "\n";
220
+ return withImport + trailingNewline + functionBlock;
221
+ }
222
+ async function defaultInstrumentationPrompt(question, defaultValue) {
223
+ if (!process.stdin.isTTY) return defaultValue;
224
+ const readline2 = await import("node:readline");
225
+ const rl = readline2.createInterface({
226
+ input: process.stdin,
227
+ output: process.stdout
228
+ });
229
+ return new Promise((resolve) => {
230
+ const suffix = defaultValue ? " [Y/n] " : " [y/N] ";
231
+ rl.question(question + suffix, (answer) => {
232
+ rl.close();
233
+ const trimmed = answer.trim().toLowerCase();
234
+ if (trimmed === "") {
235
+ resolve(defaultValue);
236
+ return;
237
+ }
238
+ resolve(trimmed === "y" || trimmed === "yes");
239
+ });
240
+ });
241
+ }
242
+ async function scaffoldInstrumentation(projectRoot, options = {}) {
243
+ const target = resolveInstrumentationTarget(projectRoot);
244
+ if (target.conflict) {
245
+ return {
246
+ action: "conflict",
247
+ // Point the user at the `src/` variant — modern Next.js apps with a
248
+ // `src/` directory load from there, so that's the merge target. The
249
+ // competing path is reported separately for the error message.
250
+ filePath: target.srcExisting[0],
251
+ conflictingPath: target.rootExisting[0]
252
+ };
253
+ }
254
+ const filePath = target.target;
255
+ const layout = target.layout;
256
+ if (filePath === null || layout === null) {
257
+ return { action: "unrecognized" };
258
+ }
259
+ const force = options.force === true;
260
+ const prompt = options.prompt ?? defaultInstrumentationPrompt;
261
+ if (!fs.existsSync(filePath)) {
262
+ const content = `import { registerGlasstrace } from "@glasstrace/sdk";
263
+
264
+ export async function register() {
265
+ // Glasstrace must be registered before Prisma instrumentation
266
+ // to ensure all ORM spans are captured correctly.
267
+ // If you use @prisma/instrumentation, import it after this call.
268
+ registerGlasstrace();
269
+ }
270
+ `;
271
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
272
+ fs.writeFileSync(filePath, content, "utf-8");
273
+ return { action: "created", filePath, layout };
274
+ }
275
+ const existing = fs.readFileSync(filePath, "utf-8");
276
+ if (hasRegisterGlasstraceCall(existing)) {
277
+ return { action: "already-registered", filePath, layout };
278
+ }
279
+ if (!force) {
280
+ const approved = await prompt(
281
+ `Merge registerGlasstrace() into ${path.relative(projectRoot, filePath)}?`,
282
+ false
283
+ );
284
+ if (!approved) {
285
+ return { action: "skipped", filePath, layout };
286
+ }
287
+ }
288
+ const injectResult = injectRegisterGlasstrace(existing);
289
+ if (injectResult.injected) {
290
+ fs.writeFileSync(filePath, injectResult.content, "utf-8");
291
+ return { action: "injected", filePath, layout };
292
+ }
293
+ const appended = appendRegisterFunction(existing);
294
+ fs.writeFileSync(filePath, appended, "utf-8");
295
+ return { action: "appended", filePath, layout };
296
+ }
297
+ async function scaffoldNextConfig(projectRoot) {
298
+ let configPath;
299
+ let configName;
300
+ for (const name of NEXT_CONFIG_NAMES) {
301
+ const candidate = path.join(projectRoot, name);
302
+ if (fs.existsSync(candidate)) {
303
+ configPath = candidate;
304
+ configName = name;
305
+ break;
306
+ }
307
+ }
308
+ if (configPath === void 0 || configName === void 0) {
309
+ return null;
310
+ }
311
+ const existing = fs.readFileSync(configPath, "utf-8");
312
+ if (existing.trim().length === 0) {
313
+ return { modified: false, reason: "empty-file" };
314
+ }
315
+ if (existing.includes("withGlasstraceConfig")) {
316
+ return { modified: false, reason: "already-wrapped" };
317
+ }
318
+ const isESM = configName.endsWith(".ts") || configName.endsWith(".mjs");
319
+ if (isESM) {
320
+ const importLine = 'import { withGlasstraceConfig } from "@glasstrace/sdk";\n';
321
+ const wrapResult2 = wrapExport(existing);
322
+ if (!wrapResult2.wrapped) {
323
+ return { modified: false, reason: "no-export" };
324
+ }
325
+ const modified2 = importLine + "\n" + wrapResult2.content;
326
+ fs.writeFileSync(configPath, modified2, "utf-8");
327
+ return { modified: true };
328
+ }
329
+ const requireLine = 'const { withGlasstraceConfig } = require("@glasstrace/sdk");\n';
330
+ const wrapResult = wrapCJSExport(existing);
331
+ if (!wrapResult.wrapped) {
332
+ return { modified: false, reason: "no-export" };
333
+ }
334
+ const modified = requireLine + "\n" + wrapResult.content;
335
+ fs.writeFileSync(configPath, modified, "utf-8");
336
+ return { modified: true };
337
+ }
338
+ function wrapExport(content) {
339
+ const marker = "export default";
340
+ const idx = content.lastIndexOf(marker);
341
+ if (idx === -1) {
342
+ return { content, wrapped: false };
343
+ }
344
+ const preamble = content.slice(0, idx);
345
+ const exprRaw = content.slice(idx + marker.length);
346
+ const expr = exprRaw.trim().replace(/;?\s*$/, "");
347
+ if (expr.length === 0) {
348
+ return { content, wrapped: false };
349
+ }
350
+ return {
351
+ content: preamble + `export default withGlasstraceConfig(${expr});
352
+ `,
353
+ wrapped: true
354
+ };
355
+ }
356
+ function wrapCJSExport(content) {
357
+ const cjsMarker = "module.exports";
358
+ const cjsIdx = content.lastIndexOf(cjsMarker);
359
+ if (cjsIdx === -1) {
360
+ return { content, wrapped: false };
361
+ }
362
+ const preamble = content.slice(0, cjsIdx);
363
+ const afterMarker = content.slice(cjsIdx + cjsMarker.length);
364
+ const eqMatch = /^\s*=\s*/.exec(afterMarker);
365
+ if (!eqMatch) {
366
+ return { content, wrapped: false };
367
+ }
368
+ const exprRaw = afterMarker.slice(eqMatch[0].length);
369
+ const expr = exprRaw.trim().replace(/;?\s*$/, "");
370
+ if (expr.length === 0) {
371
+ return { content, wrapped: false };
372
+ }
373
+ return {
374
+ content: preamble + `module.exports = withGlasstraceConfig(${expr});
375
+ `,
376
+ wrapped: true
377
+ };
378
+ }
379
+ async function scaffoldEnvLocal(projectRoot) {
380
+ const filePath = path.join(projectRoot, ".env.local");
381
+ if (fs.existsSync(filePath)) {
382
+ const existing = fs.readFileSync(filePath, "utf-8");
383
+ if (/^\s*#?\s*GLASSTRACE_API_KEY\s*=/m.test(existing)) {
384
+ return false;
385
+ }
386
+ const separator = existing.endsWith("\n") ? "" : "\n";
387
+ fs.writeFileSync(filePath, existing + separator + "# GLASSTRACE_API_KEY=your_key_here\n", "utf-8");
388
+ return true;
389
+ }
390
+ fs.writeFileSync(filePath, "# GLASSTRACE_API_KEY=your_key_here\n", "utf-8");
391
+ return true;
392
+ }
393
+ async function addCoverageMapEnv(projectRoot) {
394
+ const filePath = path.join(projectRoot, ".env.local");
395
+ if (!fs.existsSync(filePath)) {
396
+ fs.writeFileSync(filePath, "GLASSTRACE_COVERAGE_MAP=true\n", "utf-8");
397
+ return true;
398
+ }
399
+ const existing = fs.readFileSync(filePath, "utf-8");
400
+ const keyRegex = /^(\s*GLASSTRACE_COVERAGE_MAP\s*=\s*)(.*)$/m;
401
+ const keyMatch = keyRegex.exec(existing);
402
+ if (keyMatch) {
403
+ const currentValue = keyMatch[2].trim();
404
+ if (currentValue === "true") {
405
+ return false;
406
+ }
407
+ const updated = existing.replace(keyRegex, `${keyMatch[1]}true`);
408
+ fs.writeFileSync(filePath, updated, "utf-8");
409
+ return true;
410
+ }
411
+ const separator = existing.endsWith("\n") ? "" : "\n";
412
+ fs.writeFileSync(filePath, existing + separator + "GLASSTRACE_COVERAGE_MAP=true\n", "utf-8");
413
+ return true;
414
+ }
415
+ async function scaffoldGitignore(projectRoot) {
416
+ const filePath = path.join(projectRoot, ".gitignore");
417
+ if (fs.existsSync(filePath)) {
418
+ const existing = fs.readFileSync(filePath, "utf-8");
419
+ const lines = existing.split("\n").map((l) => l.trim());
420
+ if (lines.includes(".glasstrace/")) {
421
+ return false;
422
+ }
423
+ const separator = existing.endsWith("\n") ? "" : "\n";
424
+ fs.writeFileSync(filePath, existing + separator + ".glasstrace/\n", "utf-8");
425
+ return true;
426
+ }
427
+ fs.writeFileSync(filePath, ".glasstrace/\n", "utf-8");
428
+ return true;
429
+ }
430
+
431
+ // src/cli/init.ts
61
432
  function meetsNodeVersion(minMajor) {
62
433
  const [major] = process.versions.node.split(".").map(Number);
63
434
  return major >= minMajor;
@@ -65,8 +436,8 @@ function meetsNodeVersion(minMajor) {
65
436
  async function decideMcpConfigAction(options) {
66
437
  const { configPath, expectedContent, force } = options;
67
438
  if (configPath === null) return "write";
68
- const exists = options.existsSync ?? fs.existsSync;
69
- const read = options.readFile ?? ((p) => fs.readFileSync(p, "utf-8"));
439
+ const exists = options.existsSync ?? fs2.existsSync;
440
+ const read = options.readFile ?? ((p) => fs2.readFileSync(p, "utf-8"));
70
441
  const prompt = options.prompt ?? promptYesNo;
71
442
  if (!exists(configPath)) return "write";
72
443
  let existingContent;
@@ -163,17 +534,17 @@ async function rollbackSteps(steps, projectRoot, state) {
163
534
  try {
164
535
  switch (step) {
165
536
  case "instrumentation": {
166
- const instrPath = state?.instrumentationPath ?? path.join(projectRoot, "instrumentation.ts");
167
- if (fs.existsSync(instrPath)) {
168
- const content = fs.readFileSync(instrPath, "utf-8");
537
+ const instrPath = state?.instrumentationPath ?? path2.join(projectRoot, "instrumentation.ts");
538
+ if (fs2.existsSync(instrPath)) {
539
+ const content = fs2.readFileSync(instrPath, "utf-8");
169
540
  if (isInitCreatedInstrumentation(content)) {
170
- fs.unlinkSync(instrPath);
541
+ fs2.unlinkSync(instrPath);
171
542
  } else if (state?.originalInstrumentationContent !== void 0) {
172
- fs.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
543
+ fs2.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
173
544
  } else {
174
545
  const cleaned = removeRegisterGlasstrace(content);
175
546
  if (cleaned !== content) {
176
- fs.writeFileSync(instrPath, cleaned, "utf-8");
547
+ fs2.writeFileSync(instrPath, cleaned, "utf-8");
177
548
  }
178
549
  }
179
550
  }
@@ -181,11 +552,11 @@ async function rollbackSteps(steps, projectRoot, state) {
181
552
  }
182
553
  case "next-config": {
183
554
  for (const name of NEXT_CONFIG_NAMES) {
184
- const configPath = path.join(projectRoot, name);
185
- if (!fs.existsSync(configPath)) {
555
+ const configPath = path2.join(projectRoot, name);
556
+ if (!fs2.existsSync(configPath)) {
186
557
  continue;
187
558
  }
188
- const content = fs.readFileSync(configPath, "utf-8");
559
+ const content = fs2.readFileSync(configPath, "utf-8");
189
560
  if (!content.includes("withGlasstraceConfig")) {
190
561
  continue;
191
562
  }
@@ -193,16 +564,16 @@ async function rollbackSteps(steps, projectRoot, state) {
193
564
  const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
194
565
  if (unwrapResult.unwrapped) {
195
566
  const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
196
- fs.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), "utf-8");
567
+ fs2.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), "utf-8");
197
568
  }
198
569
  break;
199
570
  }
200
571
  break;
201
572
  }
202
573
  case "env-local": {
203
- const envPath = path.join(projectRoot, ".env.local");
204
- if (fs.existsSync(envPath)) {
205
- const content = fs.readFileSync(envPath, "utf-8");
574
+ const envPath = path2.join(projectRoot, ".env.local");
575
+ if (fs2.existsSync(envPath)) {
576
+ const content = fs2.readFileSync(envPath, "utf-8");
206
577
  const lines = content.split("\n");
207
578
  const filtered = lines.filter((line) => {
208
579
  const trimmed = line.trim();
@@ -211,18 +582,18 @@ async function rollbackSteps(steps, projectRoot, state) {
211
582
  if (filtered.length !== lines.length) {
212
583
  const result = filtered.join("\n");
213
584
  if (result.trim().length === 0) {
214
- fs.unlinkSync(envPath);
585
+ fs2.unlinkSync(envPath);
215
586
  } else {
216
- fs.writeFileSync(envPath, result, "utf-8");
587
+ fs2.writeFileSync(envPath, result, "utf-8");
217
588
  }
218
589
  }
219
590
  }
220
591
  break;
221
592
  }
222
593
  case "gitignore": {
223
- const gitignorePath = path.join(projectRoot, ".gitignore");
224
- if (fs.existsSync(gitignorePath)) {
225
- const content = fs.readFileSync(gitignorePath, "utf-8");
594
+ const gitignorePath = path2.join(projectRoot, ".gitignore");
595
+ if (fs2.existsSync(gitignorePath)) {
596
+ const content = fs2.readFileSync(gitignorePath, "utf-8");
226
597
  const lines = content.split("\n");
227
598
  const filtered = lines.filter(
228
599
  (line) => line.trim() !== ".glasstrace/"
@@ -230,9 +601,9 @@ async function rollbackSteps(steps, projectRoot, state) {
230
601
  if (filtered.length !== lines.length) {
231
602
  const result = filtered.join("\n");
232
603
  if (result.trim().length === 0) {
233
- fs.unlinkSync(gitignorePath);
604
+ fs2.unlinkSync(gitignorePath);
234
605
  } else {
235
- fs.writeFileSync(gitignorePath, result, "utf-8");
606
+ fs2.writeFileSync(gitignorePath, result, "utf-8");
236
607
  }
237
608
  }
238
609
  }
@@ -263,8 +634,8 @@ async function runInit(options) {
263
634
  errors.push(err instanceof Error ? err.message : String(err));
264
635
  return { exitCode: 1, summary, warnings, errors };
265
636
  }
266
- const packageJsonPath = path.join(projectRoot, "package.json");
267
- if (!fs.existsSync(packageJsonPath)) {
637
+ const packageJsonPath = path2.join(projectRoot, "package.json");
638
+ if (!fs2.existsSync(packageJsonPath)) {
268
639
  errors.push("No package.json found. Run this command from a Node.js project root.");
269
640
  return { exitCode: 1, summary, warnings, errors };
270
641
  }
@@ -273,8 +644,8 @@ async function runInit(options) {
273
644
  const preResolved = resolveInstrumentationTarget(projectRoot);
274
645
  if (!preResolved.conflict && preResolved.target !== null) {
275
646
  rollbackState.instrumentationPath = preResolved.target;
276
- if (fs.existsSync(preResolved.target)) {
277
- rollbackState.originalInstrumentationContent = fs.readFileSync(
647
+ if (fs2.existsSync(preResolved.target)) {
648
+ rollbackState.originalInstrumentationContent = fs2.readFileSync(
278
649
  preResolved.target,
279
650
  "utf-8"
280
651
  );
@@ -289,7 +660,7 @@ async function runInit(options) {
289
660
  if (instrResult.filePath !== void 0) {
290
661
  rollbackState.instrumentationPath = instrResult.filePath;
291
662
  }
292
- const relativePath = instrResult.filePath !== void 0 ? path.relative(projectRoot, instrResult.filePath) : "instrumentation.ts";
663
+ const relativePath = instrResult.filePath !== void 0 ? path2.relative(projectRoot, instrResult.filePath) : "instrumentation.ts";
293
664
  switch (instrResult.action) {
294
665
  case "created":
295
666
  summary.push(`Created ${relativePath}`);
@@ -314,8 +685,8 @@ async function runInit(options) {
314
685
  );
315
686
  break;
316
687
  case "conflict": {
317
- const primary = instrResult.filePath !== void 0 ? path.relative(projectRoot, instrResult.filePath) : "src/instrumentation.ts";
318
- const competing = instrResult.conflictingPath !== void 0 ? path.relative(projectRoot, instrResult.conflictingPath) : "instrumentation.ts";
688
+ const primary = instrResult.filePath !== void 0 ? path2.relative(projectRoot, instrResult.filePath) : "src/instrumentation.ts";
689
+ const competing = instrResult.conflictingPath !== void 0 ? path2.relative(projectRoot, instrResult.conflictingPath) : "instrumentation.ts";
319
690
  await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);
320
691
  errors.push(
321
692
  `Both ${primary} and ${competing} exist. Next.js's loader behavior is undefined when both are present.
@@ -362,10 +733,10 @@ Then add this as the first statement in your register() function:
362
733
  return { exitCode: 1, summary, warnings, errors };
363
734
  }
364
735
  try {
365
- const envPathForCheck = path.join(projectRoot, ".env.local");
736
+ const envPathForCheck = path2.join(projectRoot, ".env.local");
366
737
  let existingDevKey = false;
367
- if (fs.existsSync(envPathForCheck)) {
368
- const existingContent = fs.readFileSync(envPathForCheck, "utf-8");
738
+ if (fs2.existsSync(envPathForCheck)) {
739
+ const existingContent = fs2.readFileSync(envPathForCheck, "utf-8");
369
740
  existingDevKey = isDevApiKey(readEnvLocalApiKey(existingContent));
370
741
  }
371
742
  const envCreated = await scaffoldEnvLocal(projectRoot);
@@ -430,10 +801,10 @@ Then add this as the first statement in your register() function:
430
801
  );
431
802
  break;
432
803
  }
433
- const gitignorePath = path.join(projectRoot, ".gitignore");
434
- if (fs.existsSync(gitignorePath)) {
804
+ const gitignorePath = path2.join(projectRoot, ".gitignore");
805
+ if (fs2.existsSync(gitignorePath)) {
435
806
  try {
436
- const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
807
+ const gitignoreContent = fs2.readFileSync(gitignorePath, "utf-8");
437
808
  if (gitignoreExcludesDiscoveryFile(gitignoreContent, discoveryResult.layout)) {
438
809
  warnings.push(
439
810
  `Your .gitignore excludes ${relPath} (directly or via a parent rule). The discovery file must be committed for the Glasstrace browser extension to find it in deployed builds. Remove the matching line from .gitignore or add an explicit negation (e.g. \`!` + relPath + "`)."
@@ -456,7 +827,7 @@ Then add this as the first statement in your register() function:
456
827
  if (isCI) {
457
828
  const genericAgent = {
458
829
  name: "generic",
459
- mcpConfigPath: path.join(projectRoot, ".glasstrace", "mcp.json"),
830
+ mcpConfigPath: path2.join(projectRoot, ".glasstrace", "mcp.json"),
460
831
  infoFilePath: null,
461
832
  cliAvailable: false,
462
833
  registrationCommand: null
@@ -469,11 +840,11 @@ Then add this as the first statement in your register() function:
469
840
  });
470
841
  if (decision !== "skip") {
471
842
  await writeMcpConfig(genericAgent, genericConfig, projectRoot);
472
- if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {
843
+ if (genericAgent.mcpConfigPath !== null && fs2.existsSync(genericAgent.mcpConfigPath)) {
473
844
  anyConfigRewrittenWithBearer = true;
474
845
  }
475
846
  }
476
- if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {
847
+ if (genericAgent.mcpConfigPath !== null && fs2.existsSync(genericAgent.mcpConfigPath)) {
477
848
  anyConfigWritten = true;
478
849
  summary.push("Created .glasstrace/mcp.json (CI mode)");
479
850
  }
@@ -487,14 +858,14 @@ Then add this as the first statement in your register() function:
487
858
  );
488
859
  const genericAgent = {
489
860
  name: "generic",
490
- mcpConfigPath: path.join(projectRoot, ".glasstrace", "mcp.json"),
861
+ mcpConfigPath: path2.join(projectRoot, ".glasstrace", "mcp.json"),
491
862
  infoFilePath: null,
492
863
  cliAvailable: false,
493
864
  registrationCommand: null
494
865
  };
495
866
  const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, bearer);
496
867
  await writeMcpConfig(genericAgent, genericConfig, projectRoot);
497
- if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {
868
+ if (genericAgent.mcpConfigPath !== null && fs2.existsSync(genericAgent.mcpConfigPath)) {
498
869
  anyConfigWritten = true;
499
870
  anyConfigRewrittenWithBearer = true;
500
871
  }
@@ -513,13 +884,13 @@ Then add this as the first statement in your register() function:
513
884
  summary.push(
514
885
  `Preserved existing ${agent.mcpConfigPath ?? agent.name} (user declined overwrite)`
515
886
  );
516
- if (agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath)) {
887
+ if (agent.mcpConfigPath !== null && fs2.existsSync(agent.mcpConfigPath)) {
517
888
  anyConfigWritten = true;
518
889
  }
519
890
  continue;
520
891
  }
521
892
  await writeMcpConfig(agent, configContent, projectRoot);
522
- const configExists = agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath);
893
+ const configExists = agent.mcpConfigPath !== null && fs2.existsSync(agent.mcpConfigPath);
523
894
  if (!configExists) {
524
895
  continue;
525
896
  }
@@ -611,9 +982,9 @@ async function verifyAnonKeyRegistration(projectRoot) {
611
982
  }
612
983
  let devKey;
613
984
  try {
614
- const envPath = path.join(projectRoot, ".env.local");
615
- if (fs.existsSync(envPath)) {
616
- const envContent = fs.readFileSync(envPath, "utf-8");
985
+ const envPath = path2.join(projectRoot, ".env.local");
986
+ if (fs2.existsSync(envPath)) {
987
+ const envContent = fs2.readFileSync(envPath, "utf-8");
617
988
  const effective = readEnvLocalApiKey(envContent);
618
989
  if (effective !== null && isDevApiKey(effective)) {
619
990
  devKey = effective;
@@ -623,7 +994,7 @@ async function verifyAnonKeyRegistration(projectRoot) {
623
994
  }
624
995
  const baseConfig = resolveConfig({ apiKey: devKey });
625
996
  const config = { ...baseConfig, apiKey: devKey };
626
- const sdkVersion = true ? "1.1.1" : "0.0.0-dev";
997
+ const sdkVersion = true ? "1.1.3" : "0.0.0-dev";
627
998
  const result = await verifyInitReachable(config, anonKey, sdkVersion);
628
999
  if (result.ok) {
629
1000
  return { outcome: "verified" };
@@ -672,7 +1043,7 @@ function parseArgs(argv) {
672
1043
  };
673
1044
  }
674
1045
  var scriptPath = typeof process !== "undefined" && process.argv[1] !== void 0 ? process.argv[1].replace(/\\/g, "/") : void 0;
675
- var scriptBasename = scriptPath !== void 0 ? path.basename(scriptPath) : void 0;
1046
+ var scriptBasename = scriptPath !== void 0 ? path2.basename(scriptPath) : void 0;
676
1047
  var isDirectExecution = scriptPath !== void 0 && (scriptPath.endsWith("/cli/init.js") || scriptPath.endsWith("/cli/init.ts") || scriptBasename === "glasstrace");
677
1048
  if (isDirectExecution) {
678
1049
  if (!meetsNodeVersion(20)) {
@@ -819,7 +1190,7 @@ Usage: glasstrace mcp add [--force] [--dry-run]
819
1190
  } else if (subcommand === "status") {
820
1191
  const remainingArgs = process.argv.slice(3);
821
1192
  const json = remainingArgs.includes("--json");
822
- Promise.all([import("./status.js"), import("../monorepo-GSL6JD3G.js")]).then(([{ runStatus }, { resolveProjectRoot: resolve }]) => {
1193
+ Promise.all([import("./status.js"), import("../monorepo-PFVNPQ6X.js")]).then(([{ runStatus }, { resolveProjectRoot: resolve }]) => {
823
1194
  let projectRoot = process.cwd();
824
1195
  try {
825
1196
  projectRoot = resolve(projectRoot).projectRoot;