@glasstrace/sdk 0.14.1 → 0.15.1

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 (40) hide show
  1. package/dist/{chunk-ERGEG4ZQ.js → chunk-2LDBR3F3.js} +16 -3
  2. package/dist/chunk-2LDBR3F3.js.map +1 -0
  3. package/dist/chunk-A2AZL6MZ.js +309 -0
  4. package/dist/chunk-A2AZL6MZ.js.map +1 -0
  5. package/dist/{chunk-ARAOZCZT.js → chunk-ROFOJQWN.js} +118 -16
  6. package/dist/chunk-ROFOJQWN.js.map +1 -0
  7. package/dist/{chunk-WV3NIPWJ.js → chunk-ZNOD6FC7.js} +18 -276
  8. package/dist/chunk-ZNOD6FC7.js.map +1 -0
  9. package/dist/cli/init.cjs +458 -115
  10. package/dist/cli/init.cjs.map +1 -1
  11. package/dist/cli/init.d.cts +33 -1
  12. package/dist/cli/init.d.ts +33 -1
  13. package/dist/cli/init.js +144 -42
  14. package/dist/cli/init.js.map +1 -1
  15. package/dist/cli/mcp-add.cjs.map +1 -1
  16. package/dist/cli/mcp-add.js +4 -2
  17. package/dist/cli/mcp-add.js.map +1 -1
  18. package/dist/cli/uninit.cjs +181 -60
  19. package/dist/cli/uninit.cjs.map +1 -1
  20. package/dist/cli/uninit.d.cts +38 -8
  21. package/dist/cli/uninit.d.ts +38 -8
  22. package/dist/cli/uninit.js +6 -3
  23. package/dist/cli/validate.cjs +135 -0
  24. package/dist/cli/validate.cjs.map +1 -0
  25. package/dist/cli/validate.d.cts +60 -0
  26. package/dist/cli/validate.d.ts +60 -0
  27. package/dist/cli/validate.js +103 -0
  28. package/dist/cli/validate.js.map +1 -0
  29. package/dist/index.cjs +123 -47
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +45 -5
  32. package/dist/index.d.ts +45 -5
  33. package/dist/index.js +109 -46
  34. package/dist/index.js.map +1 -1
  35. package/dist/{source-map-uploader-W6VPGY26.js → source-map-uploader-3GWUQDTS.js} +6 -2
  36. package/package.json +6 -4
  37. package/dist/chunk-ARAOZCZT.js.map +0 -1
  38. package/dist/chunk-ERGEG4ZQ.js.map +0 -1
  39. package/dist/chunk-WV3NIPWJ.js.map +0 -1
  40. /package/dist/{source-map-uploader-W6VPGY26.js.map → source-map-uploader-3GWUQDTS.js.map} +0 -0
package/dist/cli/init.cjs CHANGED
@@ -83,14 +83,14 @@ function injectRegisterGlasstrace(content) {
83
83
  const indentMatch = /\n([ \t]+)/.exec(afterBrace);
84
84
  const indent = indentMatch ? indentMatch[1] : " ";
85
85
  const importLine = 'import { registerGlasstrace } from "@glasstrace/sdk";\n';
86
- const hasGlasstraceImport = content.includes("@glasstrace/sdk");
86
+ const hasGlasstraceImport2 = content.includes("@glasstrace/sdk");
87
87
  const insertPoint = match.index + match[0].length;
88
88
  const callInjection = `
89
89
  ${indent}// Glasstrace must be registered before other instrumentation
90
90
  ${indent}registerGlasstrace();
91
91
  `;
92
92
  let modified;
93
- if (hasGlasstraceImport) {
93
+ if (hasGlasstraceImport2) {
94
94
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']@glasstrace\/sdk["']/;
95
95
  const importMatch = importRegex.exec(content);
96
96
  if (importMatch) {
@@ -230,6 +230,23 @@ function wrapCJSExport(content) {
230
230
  wrapped: true
231
231
  };
232
232
  }
233
+ function readEnvLocalApiKey(content) {
234
+ let last = null;
235
+ const regex = /^\s*GLASSTRACE_API_KEY\s*=\s*(.*)$/gm;
236
+ let match;
237
+ while ((match = regex.exec(content)) !== null) {
238
+ const raw = match[1].trim();
239
+ if (raw === "") continue;
240
+ const unquoted = raw.replace(/^(['"])(.*)\1$/, "$2");
241
+ if (unquoted === "" || unquoted === "your_key_here") continue;
242
+ last = unquoted;
243
+ }
244
+ return last;
245
+ }
246
+ function isDevApiKey(value) {
247
+ if (value === null || value === void 0) return false;
248
+ return value.trim().startsWith("gt_dev_");
249
+ }
233
250
  async function scaffoldEnvLocal(projectRoot) {
234
251
  const filePath = path.join(projectRoot, ".env.local");
235
252
  if (fs.existsSync(filePath)) {
@@ -281,6 +298,30 @@ async function scaffoldGitignore(projectRoot) {
281
298
  fs.writeFileSync(filePath, ".glasstrace/\n", "utf-8");
282
299
  return true;
283
300
  }
301
+ function mcpConfigMatches(existingContent, expectedContent) {
302
+ const trimmedExpected = expectedContent.trim();
303
+ try {
304
+ const existingParsed = JSON.parse(existingContent);
305
+ const expectedParsed = JSON.parse(trimmedExpected);
306
+ return JSON.stringify(canonicalize(existingParsed)) === JSON.stringify(canonicalize(expectedParsed));
307
+ } catch {
308
+ }
309
+ return existingContent.trim() === trimmedExpected;
310
+ }
311
+ function canonicalize(value) {
312
+ if (Array.isArray(value)) {
313
+ return value.map(canonicalize);
314
+ }
315
+ if (value !== null && typeof value === "object") {
316
+ const obj = value;
317
+ const sorted = {};
318
+ for (const key of Object.keys(obj).sort()) {
319
+ sorted[key] = canonicalize(obj[key]);
320
+ }
321
+ return sorted;
322
+ }
323
+ return value;
324
+ }
284
325
  async function scaffoldMcpMarker(projectRoot, anonKey) {
285
326
  const dirPath = path.join(projectRoot, ".glasstrace");
286
327
  const markerPath = path.join(dirPath, "mcp-connected");
@@ -570,10 +611,10 @@ function mergeDefs(...defs) {
570
611
  function cloneDef(schema) {
571
612
  return mergeDefs(schema._zod.def);
572
613
  }
573
- function getElementAtPath(obj, path8) {
574
- if (!path8)
614
+ function getElementAtPath(obj, path9) {
615
+ if (!path9)
575
616
  return obj;
576
- return path8.reduce((acc, key) => acc?.[key], obj);
617
+ return path9.reduce((acc, key) => acc?.[key], obj);
577
618
  }
578
619
  function promiseAllObject(promisesObj) {
579
620
  const keys = Object.keys(promisesObj);
@@ -885,11 +926,11 @@ function aborted(x, startIndex = 0) {
885
926
  }
886
927
  return false;
887
928
  }
888
- function prefixIssues(path8, issues) {
929
+ function prefixIssues(path9, issues) {
889
930
  return issues.map((iss) => {
890
931
  var _a2;
891
932
  (_a2 = iss).path ?? (_a2.path = []);
892
- iss.path.unshift(path8);
933
+ iss.path.unshift(path9);
893
934
  return iss;
894
935
  });
895
936
  }
@@ -1133,7 +1174,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
1133
1174
  }
1134
1175
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
1135
1176
  const result = { errors: [] };
1136
- const processError = (error49, path8 = []) => {
1177
+ const processError = (error49, path9 = []) => {
1137
1178
  var _a2, _b;
1138
1179
  for (const issue2 of error49.issues) {
1139
1180
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -1143,7 +1184,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1143
1184
  } else if (issue2.code === "invalid_element") {
1144
1185
  processError({ issues: issue2.issues }, issue2.path);
1145
1186
  } else {
1146
- const fullpath = [...path8, ...issue2.path];
1187
+ const fullpath = [...path9, ...issue2.path];
1147
1188
  if (fullpath.length === 0) {
1148
1189
  result.errors.push(mapper(issue2));
1149
1190
  continue;
@@ -1175,8 +1216,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1175
1216
  }
1176
1217
  function toDotPath(_path) {
1177
1218
  const segs = [];
1178
- const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1179
- for (const seg of path8) {
1219
+ const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1220
+ for (const seg of path9) {
1180
1221
  if (typeof seg === "number")
1181
1222
  segs.push(`[${seg}]`);
1182
1223
  else if (typeof seg === "symbol")
@@ -14010,13 +14051,13 @@ function resolveRef(ref, ctx) {
14010
14051
  if (!ref.startsWith("#")) {
14011
14052
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14012
14053
  }
14013
- const path8 = ref.slice(1).split("/").filter(Boolean);
14014
- if (path8.length === 0) {
14054
+ const path9 = ref.slice(1).split("/").filter(Boolean);
14055
+ if (path9.length === 0) {
14015
14056
  return ctx.rootSchema;
14016
14057
  }
14017
14058
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14018
- if (path8[0] === defsKey) {
14019
- const key = path8[1];
14059
+ if (path9[0] === defsKey) {
14060
+ const key = path9[1];
14020
14061
  if (!key || !ctx.defs[key]) {
14021
14062
  throw new Error(`Reference not found: ${ref}`);
14022
14063
  }
@@ -14935,11 +14976,11 @@ var init_dist = __esm({
14935
14976
  async function loadFsPath() {
14936
14977
  if (fsPathCache !== void 0) return fsPathCache;
14937
14978
  try {
14938
- const [fs8, path8] = await Promise.all([
14979
+ const [fs9, path9] = await Promise.all([
14939
14980
  import("fs/promises"),
14940
14981
  import("path")
14941
14982
  ]);
14942
- fsPathCache = { fs: fs8, path: path8 };
14983
+ fsPathCache = { fs: fs9, path: path9 };
14943
14984
  return fsPathCache;
14944
14985
  } catch {
14945
14986
  fsPathCache = null;
@@ -15027,9 +15068,9 @@ var init_anon_key = __esm({
15027
15068
  });
15028
15069
 
15029
15070
  // src/agent-detection/detect.ts
15030
- async function pathExists(path8, mode = import_node_fs.constants.R_OK) {
15071
+ async function pathExists(path9, mode = import_node_fs.constants.R_OK) {
15031
15072
  try {
15032
- await (0, import_promises.access)(path8, mode);
15073
+ await (0, import_promises.access)(path9, mode);
15033
15074
  return true;
15034
15075
  } catch {
15035
15076
  return false;
@@ -15798,7 +15839,8 @@ __export(uninit_exports, {
15798
15839
  runUninit: () => runUninit,
15799
15840
  skipString: () => skipString,
15800
15841
  unwrapCJSExport: () => unwrapCJSExport,
15801
- unwrapExport: () => unwrapExport
15842
+ unwrapExport: () => unwrapExport,
15843
+ writeShutdownMarker: () => writeShutdownMarker
15802
15844
  });
15803
15845
  function skipString(text, start, quote) {
15804
15846
  let i = start + 1;
@@ -16099,12 +16141,75 @@ function processTomlMcpConfig(content) {
16099
16141
  }
16100
16142
  return { action: "removed-section", content: result + "\n" };
16101
16143
  }
16144
+ function writeShutdownMarker(projectRoot) {
16145
+ const dirPath = path4.join(projectRoot, ".glasstrace");
16146
+ if (!fs4.existsSync(dirPath)) {
16147
+ return false;
16148
+ }
16149
+ const markerPath = path4.join(dirPath, "shutdown-requested");
16150
+ const tmpPath = `${markerPath}.tmp`;
16151
+ const body = JSON.stringify({ requestedAt: (/* @__PURE__ */ new Date()).toISOString() });
16152
+ try {
16153
+ fs4.writeFileSync(tmpPath, body, { encoding: "utf-8", mode: 384 });
16154
+ try {
16155
+ fs4.chmodSync(tmpPath, 384);
16156
+ } catch {
16157
+ }
16158
+ fs4.renameSync(tmpPath, markerPath);
16159
+ return true;
16160
+ } catch {
16161
+ try {
16162
+ fs4.unlinkSync(tmpPath);
16163
+ } catch {
16164
+ }
16165
+ return false;
16166
+ }
16167
+ }
16168
+ async function defaultPrompt(question, defaultValue) {
16169
+ if (!process.stdin.isTTY) return defaultValue;
16170
+ const readline2 = await import("readline");
16171
+ const rl = readline2.createInterface({
16172
+ input: process.stdin,
16173
+ output: process.stdout
16174
+ });
16175
+ return new Promise((resolve2) => {
16176
+ const suffix = defaultValue ? " [Y/n] " : " [y/N] ";
16177
+ rl.question(question + suffix, (answer) => {
16178
+ rl.close();
16179
+ const trimmed = answer.trim().toLowerCase();
16180
+ if (trimmed === "") {
16181
+ resolve2(defaultValue);
16182
+ return;
16183
+ }
16184
+ resolve2(trimmed === "y" || trimmed === "yes");
16185
+ });
16186
+ });
16187
+ }
16102
16188
  async function runUninit(options) {
16103
16189
  const { projectRoot, dryRun } = options;
16190
+ const force = options.force === true;
16191
+ const prompt = options.prompt ?? defaultPrompt;
16104
16192
  const summary = [];
16105
16193
  const warnings = [];
16106
16194
  const errors = [];
16107
16195
  const prefix = dryRun ? "[dry run] " : "";
16196
+ try {
16197
+ if (!dryRun) {
16198
+ const markerWritten = writeShutdownMarker(projectRoot);
16199
+ if (markerWritten) {
16200
+ summary.push("Wrote .glasstrace/shutdown-requested marker");
16201
+ }
16202
+ } else {
16203
+ const dirPath = path4.join(projectRoot, ".glasstrace");
16204
+ if (fs4.existsSync(dirPath)) {
16205
+ summary.push(`${prefix}Would write .glasstrace/shutdown-requested marker`);
16206
+ }
16207
+ }
16208
+ } catch (err) {
16209
+ warnings.push(
16210
+ `Shutdown marker write failed: ${err instanceof Error ? err.message : String(err)}`
16211
+ );
16212
+ }
16108
16213
  try {
16109
16214
  let configHandled = false;
16110
16215
  for (const name of NEXT_CONFIG_NAMES) {
@@ -16187,23 +16292,57 @@ async function runUninit(options) {
16187
16292
  const envPath = path4.join(projectRoot, ".env.local");
16188
16293
  if (fs4.existsSync(envPath)) {
16189
16294
  const content = fs4.readFileSync(envPath, "utf-8");
16190
- const lines = content.split("\n");
16191
- const filtered = lines.filter((line) => {
16192
- const trimmed = line.trim();
16193
- return !(/^\s*#?\s*GLASSTRACE_API_KEY\s*=/.test(trimmed) || /^\s*#?\s*GLASSTRACE_COVERAGE_MAP\s*=/.test(trimmed));
16194
- });
16195
- if (filtered.length !== lines.length) {
16196
- const result = filtered.join("\n");
16197
- if (result.trim().length === 0) {
16198
- if (!dryRun) {
16199
- fs4.unlinkSync(envPath);
16200
- }
16201
- summary.push(`${prefix}Deleted .env.local (no remaining entries)`);
16295
+ const existingKey = readEnvLocalApiKey(content);
16296
+ const hasDevKey = isDevApiKey(existingKey);
16297
+ let proceed = true;
16298
+ let devKeyPath = "none";
16299
+ if (hasDevKey) {
16300
+ if (dryRun) {
16301
+ devKeyPath = "dry-run-preview";
16302
+ } else if (force) {
16303
+ devKeyPath = "force-bypass";
16202
16304
  } else {
16203
- if (!dryRun) {
16204
- fs4.writeFileSync(envPath, result, "utf-8");
16305
+ const confirmed = await prompt(
16306
+ ".env.local contains a claimed Glasstrace developer API key (gt_dev_...). Removing it will require you to re-authenticate. Continue?",
16307
+ false
16308
+ );
16309
+ proceed = confirmed;
16310
+ if (confirmed) devKeyPath = "interactive-confirmed";
16311
+ }
16312
+ }
16313
+ if (!proceed) {
16314
+ warnings.push(
16315
+ "Preserved GLASSTRACE_API_KEY in .env.local (claimed dev key; re-run with --force to remove)"
16316
+ );
16317
+ } else {
16318
+ const lines = content.split("\n");
16319
+ const filtered = lines.filter((line) => {
16320
+ const trimmed = line.trim();
16321
+ return !(/^\s*#?\s*GLASSTRACE_API_KEY\s*=/.test(trimmed) || /^\s*#?\s*GLASSTRACE_COVERAGE_MAP\s*=/.test(trimmed));
16322
+ });
16323
+ if (filtered.length !== lines.length) {
16324
+ const result = filtered.join("\n");
16325
+ if (result.trim().length === 0) {
16326
+ if (!dryRun) {
16327
+ fs4.unlinkSync(envPath);
16328
+ }
16329
+ summary.push(`${prefix}Deleted .env.local (no remaining entries)`);
16330
+ } else {
16331
+ if (!dryRun) {
16332
+ fs4.writeFileSync(envPath, result, "utf-8");
16333
+ }
16334
+ let devKeyAnnotation = "";
16335
+ if (devKeyPath === "interactive-confirmed") {
16336
+ devKeyAnnotation = " (dev key confirmed)";
16337
+ } else if (devKeyPath === "force-bypass") {
16338
+ devKeyAnnotation = " (dev key removed via --force)";
16339
+ } else if (devKeyPath === "dry-run-preview") {
16340
+ devKeyAnnotation = " (dev key would be removed; real run would require confirmation)";
16341
+ }
16342
+ summary.push(
16343
+ `${prefix}Removed GLASSTRACE entries from .env.local${devKeyAnnotation}`
16344
+ );
16205
16345
  }
16206
- summary.push(`${prefix}Removed GLASSTRACE entries from .env.local`);
16207
16346
  }
16208
16347
  }
16209
16348
  }
@@ -16359,6 +16498,7 @@ var init_uninit = __esm({
16359
16498
  os = __toESM(require("os"), 1);
16360
16499
  path4 = __toESM(require("path"), 1);
16361
16500
  init_constants();
16501
+ init_scaffolder();
16362
16502
  MCP_CONFIG_FILES = [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json"];
16363
16503
  AGENT_INFO_FILES = [
16364
16504
  "CLAUDE.md",
@@ -16599,6 +16739,112 @@ var init_mcp_add = __esm({
16599
16739
  }
16600
16740
  });
16601
16741
 
16742
+ // src/cli/validate.ts
16743
+ var validate_exports = {};
16744
+ __export(validate_exports, {
16745
+ hasGlasstraceImport: () => hasGlasstraceImport,
16746
+ hasRegisterGlasstraceImport: () => hasRegisterGlasstraceImport,
16747
+ runValidate: () => runValidate
16748
+ });
16749
+ function hasGlasstraceImport(content) {
16750
+ return /@glasstrace\/sdk/.test(content);
16751
+ }
16752
+ function hasRegisterGlasstraceImport(content) {
16753
+ const match = /import\s*\{([^}]+)\}\s*from\s*["']@glasstrace\/sdk["']/;
16754
+ const importMatch = match.exec(content);
16755
+ if (!importMatch) return false;
16756
+ return importMatch[1].split(",").map((s) => s.trim()).includes("registerGlasstrace");
16757
+ }
16758
+ function runValidate(options) {
16759
+ const { projectRoot } = options;
16760
+ const issues = [];
16761
+ const glasstraceDir = path6.join(projectRoot, ".glasstrace");
16762
+ const instrumentationPath = path6.join(projectRoot, "instrumentation.ts");
16763
+ const markerPath = path6.join(glasstraceDir, "mcp-connected");
16764
+ const glasstraceDirExists = isDirectorySafe(glasstraceDir);
16765
+ const instrumentationExists = fs6.existsSync(instrumentationPath);
16766
+ const instrumentationContent = instrumentationExists ? safeReadFile(instrumentationPath) : null;
16767
+ const markerExists = fs6.existsSync(markerPath);
16768
+ const mcpConfigsPresent = MCP_CONFIG_CANDIDATES.filter(
16769
+ (rel) => fs6.existsSync(path6.join(projectRoot, rel))
16770
+ );
16771
+ if (glasstraceDirExists) {
16772
+ if (instrumentationContent === null || !hasRegisterGlasstraceImport(instrumentationContent)) {
16773
+ issues.push({
16774
+ code: "glasstrace-dir-without-register-import",
16775
+ message: ".glasstrace/ exists but instrumentation.ts is missing the registerGlasstrace import.",
16776
+ fix: "Run `npx glasstrace init` to re-scaffold instrumentation.ts, or remove .glasstrace/ if the SDK is no longer in use."
16777
+ });
16778
+ }
16779
+ }
16780
+ if (!glasstraceDirExists && instrumentationContent !== null) {
16781
+ if (hasGlasstraceImport(instrumentationContent)) {
16782
+ issues.push({
16783
+ code: "sdk-import-without-glasstrace-dir",
16784
+ message: "instrumentation.ts imports from @glasstrace/sdk but .glasstrace/ is missing.",
16785
+ fix: "Run `npx glasstrace init` to recreate .glasstrace/, or `npx glasstrace uninit` to fully remove the SDK."
16786
+ });
16787
+ }
16788
+ }
16789
+ if (markerExists && mcpConfigsPresent.length === 0) {
16790
+ issues.push({
16791
+ code: "mcp-marker-without-configs",
16792
+ message: ".glasstrace/mcp-connected marker is present but no MCP config files were found.",
16793
+ fix: "Run `npx glasstrace mcp add --force` to regenerate MCP configs, or delete .glasstrace/mcp-connected."
16794
+ });
16795
+ }
16796
+ if (!markerExists && mcpConfigsPresent.length > 0) {
16797
+ issues.push({
16798
+ code: "mcp-configs-without-marker",
16799
+ message: `MCP config files exist (${mcpConfigsPresent.join(", ")}) but .glasstrace/mcp-connected marker is missing.`,
16800
+ fix: "Run `npx glasstrace init` to re-register the marker, or `npx glasstrace uninit` to fully remove MCP configuration."
16801
+ });
16802
+ }
16803
+ const summary = [];
16804
+ if (issues.length === 0) {
16805
+ summary.push("Glasstrace install state is consistent.");
16806
+ } else {
16807
+ summary.push(
16808
+ `Detected ${issues.length} inconsistenc${issues.length === 1 ? "y" : "ies"} in Glasstrace install state:`
16809
+ );
16810
+ }
16811
+ return {
16812
+ exitCode: issues.length > 0 ? 1 : 0,
16813
+ summary,
16814
+ issues
16815
+ };
16816
+ }
16817
+ function safeReadFile(filePath) {
16818
+ try {
16819
+ return fs6.readFileSync(filePath, "utf-8");
16820
+ } catch {
16821
+ return null;
16822
+ }
16823
+ }
16824
+ function isDirectorySafe(dirPath) {
16825
+ try {
16826
+ if (!fs6.existsSync(dirPath)) return false;
16827
+ return fs6.statSync(dirPath).isDirectory();
16828
+ } catch {
16829
+ return false;
16830
+ }
16831
+ }
16832
+ var fs6, path6, MCP_CONFIG_CANDIDATES;
16833
+ var init_validate = __esm({
16834
+ "src/cli/validate.ts"() {
16835
+ "use strict";
16836
+ init_cjs_shims();
16837
+ fs6 = __toESM(require("fs"), 1);
16838
+ path6 = __toESM(require("path"), 1);
16839
+ MCP_CONFIG_CANDIDATES = [
16840
+ ".mcp.json",
16841
+ ".cursor/mcp.json",
16842
+ ".gemini/settings.json",
16843
+ ".codex/config.toml"
16844
+ ];
16845
+ }
16846
+ });
16847
+
16602
16848
  // src/cli/status.ts
16603
16849
  var status_exports = {};
16604
16850
  __export(status_exports, {
@@ -16619,8 +16865,8 @@ function runStatus(options) {
16619
16865
  }
16620
16866
  function checkInstalled(root) {
16621
16867
  try {
16622
- const pkgPath = path6.join(root, "package.json");
16623
- const content = fs6.readFileSync(pkgPath, "utf-8");
16868
+ const pkgPath = path7.join(root, "package.json");
16869
+ const content = fs7.readFileSync(pkgPath, "utf-8");
16624
16870
  const pkg = JSON.parse(content);
16625
16871
  const deps = pkg["dependencies"];
16626
16872
  const devDeps = pkg["devDependencies"];
@@ -16631,7 +16877,7 @@ function checkInstalled(root) {
16631
16877
  }
16632
16878
  function checkInitialized(root) {
16633
16879
  try {
16634
- return fs6.statSync(path6.join(root, ".glasstrace")).isDirectory();
16880
+ return fs7.statSync(path7.join(root, ".glasstrace")).isDirectory();
16635
16881
  } catch {
16636
16882
  return false;
16637
16883
  }
@@ -16639,7 +16885,7 @@ function checkInitialized(root) {
16639
16885
  function checkInstrumentation(root) {
16640
16886
  for (const name of INSTRUMENTATION_FILES) {
16641
16887
  try {
16642
- const content = fs6.readFileSync(path6.join(root, name), "utf-8");
16888
+ const content = fs7.readFileSync(path7.join(root, name), "utf-8");
16643
16889
  if (content.includes("registerGlasstrace")) {
16644
16890
  return true;
16645
16891
  }
@@ -16651,7 +16897,7 @@ function checkInstrumentation(root) {
16651
16897
  function checkConfigWrapped(root) {
16652
16898
  for (const name of NEXT_CONFIG_NAMES) {
16653
16899
  try {
16654
- const content = fs6.readFileSync(path6.join(root, name), "utf-8");
16900
+ const content = fs7.readFileSync(path7.join(root, name), "utf-8");
16655
16901
  if (content.includes("withGlasstraceConfig")) {
16656
16902
  return true;
16657
16903
  }
@@ -16662,7 +16908,7 @@ function checkConfigWrapped(root) {
16662
16908
  }
16663
16909
  function checkAnonKey(root) {
16664
16910
  try {
16665
- return fs6.statSync(path6.join(root, ".glasstrace", "anon_key")).isFile();
16911
+ return fs7.statSync(path7.join(root, ".glasstrace", "anon_key")).isFile();
16666
16912
  } catch {
16667
16913
  return false;
16668
16914
  }
@@ -16670,7 +16916,7 @@ function checkAnonKey(root) {
16670
16916
  function checkMcpConfigured(root) {
16671
16917
  for (const name of MCP_JSON_FILES) {
16672
16918
  try {
16673
- const content = fs6.readFileSync(path6.join(root, name), "utf-8");
16919
+ const content = fs7.readFileSync(path7.join(root, name), "utf-8");
16674
16920
  const parsed = JSON.parse(content);
16675
16921
  const mcpServers = parsed["mcpServers"];
16676
16922
  if (mcpServers && typeof mcpServers === "object" && "glasstrace" in mcpServers) {
@@ -16681,7 +16927,7 @@ function checkMcpConfigured(root) {
16681
16927
  }
16682
16928
  for (const name of MCP_TOML_FILES) {
16683
16929
  try {
16684
- const content = fs6.readFileSync(path6.join(root, name), "utf-8");
16930
+ const content = fs7.readFileSync(path7.join(root, name), "utf-8");
16685
16931
  if (content.includes("[mcp_servers.glasstrace]")) {
16686
16932
  return true;
16687
16933
  }
@@ -16694,7 +16940,7 @@ function checkAgents(root) {
16694
16940
  const found = [];
16695
16941
  for (const name of AGENT_INFO_FILES2) {
16696
16942
  try {
16697
- const content = fs6.readFileSync(path6.join(root, name), "utf-8");
16943
+ const content = fs7.readFileSync(path7.join(root, name), "utf-8");
16698
16944
  const hasHtmlMarkers = content.includes("<!-- glasstrace:mcp:start -->") && content.includes("<!-- glasstrace:mcp:end -->");
16699
16945
  const hasHashMarkers = content.includes("# glasstrace:mcp:start") && content.includes("# glasstrace:mcp:end");
16700
16946
  if (hasHtmlMarkers || hasHashMarkers) {
@@ -16717,8 +16963,8 @@ function readRuntimeState(root) {
16717
16963
  pid: null
16718
16964
  };
16719
16965
  try {
16720
- const filePath = path6.join(root, ".glasstrace", "runtime-state.json");
16721
- const content = fs6.readFileSync(filePath, "utf-8");
16966
+ const filePath = path7.join(root, ".glasstrace", "runtime-state.json");
16967
+ const content = fs7.readFileSync(filePath, "utf-8");
16722
16968
  const parsed = JSON.parse(content);
16723
16969
  const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : null;
16724
16970
  const pid = typeof parsed.pid === "number" ? parsed.pid : null;
@@ -16767,13 +17013,13 @@ function readRuntimeState(root) {
16767
17013
  return empty;
16768
17014
  }
16769
17015
  }
16770
- var fs6, path6, MCP_JSON_FILES, MCP_TOML_FILES, AGENT_INFO_FILES2, INSTRUMENTATION_FILES, STALE_THRESHOLD_MS;
17016
+ var fs7, path7, MCP_JSON_FILES, MCP_TOML_FILES, AGENT_INFO_FILES2, INSTRUMENTATION_FILES, STALE_THRESHOLD_MS;
16771
17017
  var init_status = __esm({
16772
17018
  "src/cli/status.ts"() {
16773
17019
  "use strict";
16774
17020
  init_cjs_shims();
16775
- fs6 = __toESM(require("fs"), 1);
16776
- path6 = __toESM(require("path"), 1);
17021
+ fs7 = __toESM(require("fs"), 1);
17022
+ path7 = __toESM(require("path"), 1);
16777
17023
  init_constants();
16778
17024
  MCP_JSON_FILES = [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json", ".glasstrace/mcp.json"];
16779
17025
  MCP_TOML_FILES = [".codex/config.toml"];
@@ -16797,14 +17043,15 @@ var init_status = __esm({
16797
17043
  // src/cli/init.ts
16798
17044
  var init_exports = {};
16799
17045
  __export(init_exports, {
17046
+ decideMcpConfigAction: () => decideMcpConfigAction,
16800
17047
  meetsNodeVersion: () => meetsNodeVersion,
16801
17048
  rollbackSteps: () => rollbackSteps,
16802
17049
  runInit: () => runInit
16803
17050
  });
16804
17051
  module.exports = __toCommonJS(init_exports);
16805
17052
  init_cjs_shims();
16806
- var fs7 = __toESM(require("fs"), 1);
16807
- var path7 = __toESM(require("path"), 1);
17053
+ var fs8 = __toESM(require("fs"), 1);
17054
+ var path8 = __toESM(require("path"), 1);
16808
17055
  var readline = __toESM(require("readline"), 1);
16809
17056
  init_scaffolder();
16810
17057
 
@@ -16990,6 +17237,31 @@ function meetsNodeVersion(minMajor) {
16990
17237
  const [major] = process.versions.node.split(".").map(Number);
16991
17238
  return major >= minMajor;
16992
17239
  }
17240
+ async function decideMcpConfigAction(options) {
17241
+ const { configPath, expectedContent, force } = options;
17242
+ if (configPath === null) return "write";
17243
+ const exists = options.existsSync ?? fs8.existsSync;
17244
+ const read = options.readFile ?? ((p) => fs8.readFileSync(p, "utf-8"));
17245
+ const prompt = options.prompt ?? promptYesNo;
17246
+ if (!exists(configPath)) return "write";
17247
+ let existingContent;
17248
+ try {
17249
+ existingContent = read(configPath);
17250
+ } catch {
17251
+ return "write";
17252
+ }
17253
+ if (mcpConfigMatches(existingContent, expectedContent)) {
17254
+ return "write";
17255
+ }
17256
+ if (force) {
17257
+ return "force-overwrite";
17258
+ }
17259
+ const answer = await prompt(
17260
+ `Existing MCP config at ${configPath} differs from Glasstrace's template. Overwrite?`,
17261
+ false
17262
+ );
17263
+ return answer ? "force-overwrite" : "skip";
17264
+ }
16993
17265
  async function promptYesNo(question, defaultValue) {
16994
17266
  if (!process.stdin.isTTY) {
16995
17267
  return defaultValue;
@@ -17019,17 +17291,17 @@ async function rollbackSteps(steps, projectRoot, state) {
17019
17291
  try {
17020
17292
  switch (step) {
17021
17293
  case "instrumentation": {
17022
- const instrPath = path7.join(projectRoot, "instrumentation.ts");
17023
- if (fs7.existsSync(instrPath)) {
17024
- const content = fs7.readFileSync(instrPath, "utf-8");
17294
+ const instrPath = path8.join(projectRoot, "instrumentation.ts");
17295
+ if (fs8.existsSync(instrPath)) {
17296
+ const content = fs8.readFileSync(instrPath, "utf-8");
17025
17297
  if (isInitCreatedInstrumentation(content)) {
17026
- fs7.unlinkSync(instrPath);
17298
+ fs8.unlinkSync(instrPath);
17027
17299
  } else if (state?.originalInstrumentationContent !== void 0) {
17028
- fs7.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
17300
+ fs8.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
17029
17301
  } else {
17030
17302
  const cleaned = removeRegisterGlasstrace(content);
17031
17303
  if (cleaned !== content) {
17032
- fs7.writeFileSync(instrPath, cleaned, "utf-8");
17304
+ fs8.writeFileSync(instrPath, cleaned, "utf-8");
17033
17305
  }
17034
17306
  }
17035
17307
  }
@@ -17037,11 +17309,11 @@ async function rollbackSteps(steps, projectRoot, state) {
17037
17309
  }
17038
17310
  case "next-config": {
17039
17311
  for (const name of NEXT_CONFIG_NAMES) {
17040
- const configPath = path7.join(projectRoot, name);
17041
- if (!fs7.existsSync(configPath)) {
17312
+ const configPath = path8.join(projectRoot, name);
17313
+ if (!fs8.existsSync(configPath)) {
17042
17314
  continue;
17043
17315
  }
17044
- const content = fs7.readFileSync(configPath, "utf-8");
17316
+ const content = fs8.readFileSync(configPath, "utf-8");
17045
17317
  if (!content.includes("withGlasstraceConfig")) {
17046
17318
  continue;
17047
17319
  }
@@ -17049,16 +17321,16 @@ async function rollbackSteps(steps, projectRoot, state) {
17049
17321
  const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
17050
17322
  if (unwrapResult.unwrapped) {
17051
17323
  const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
17052
- fs7.writeFileSync(configPath, cleanLeadingBlankLines2(cleaned), "utf-8");
17324
+ fs8.writeFileSync(configPath, cleanLeadingBlankLines2(cleaned), "utf-8");
17053
17325
  }
17054
17326
  break;
17055
17327
  }
17056
17328
  break;
17057
17329
  }
17058
17330
  case "env-local": {
17059
- const envPath = path7.join(projectRoot, ".env.local");
17060
- if (fs7.existsSync(envPath)) {
17061
- const content = fs7.readFileSync(envPath, "utf-8");
17331
+ const envPath = path8.join(projectRoot, ".env.local");
17332
+ if (fs8.existsSync(envPath)) {
17333
+ const content = fs8.readFileSync(envPath, "utf-8");
17062
17334
  const lines = content.split("\n");
17063
17335
  const filtered = lines.filter((line) => {
17064
17336
  const trimmed = line.trim();
@@ -17067,18 +17339,18 @@ async function rollbackSteps(steps, projectRoot, state) {
17067
17339
  if (filtered.length !== lines.length) {
17068
17340
  const result = filtered.join("\n");
17069
17341
  if (result.trim().length === 0) {
17070
- fs7.unlinkSync(envPath);
17342
+ fs8.unlinkSync(envPath);
17071
17343
  } else {
17072
- fs7.writeFileSync(envPath, result, "utf-8");
17344
+ fs8.writeFileSync(envPath, result, "utf-8");
17073
17345
  }
17074
17346
  }
17075
17347
  }
17076
17348
  break;
17077
17349
  }
17078
17350
  case "gitignore": {
17079
- const gitignorePath = path7.join(projectRoot, ".gitignore");
17080
- if (fs7.existsSync(gitignorePath)) {
17081
- const content = fs7.readFileSync(gitignorePath, "utf-8");
17351
+ const gitignorePath = path8.join(projectRoot, ".gitignore");
17352
+ if (fs8.existsSync(gitignorePath)) {
17353
+ const content = fs8.readFileSync(gitignorePath, "utf-8");
17082
17354
  const lines = content.split("\n");
17083
17355
  const filtered = lines.filter(
17084
17356
  (line) => line.trim() !== ".glasstrace/"
@@ -17086,9 +17358,9 @@ async function rollbackSteps(steps, projectRoot, state) {
17086
17358
  if (filtered.length !== lines.length) {
17087
17359
  const result = filtered.join("\n");
17088
17360
  if (result.trim().length === 0) {
17089
- fs7.unlinkSync(gitignorePath);
17361
+ fs8.unlinkSync(gitignorePath);
17090
17362
  } else {
17091
- fs7.writeFileSync(gitignorePath, result, "utf-8");
17363
+ fs8.writeFileSync(gitignorePath, result, "utf-8");
17092
17364
  }
17093
17365
  }
17094
17366
  }
@@ -17115,16 +17387,16 @@ async function runInit(options) {
17115
17387
  errors.push(err instanceof Error ? err.message : String(err));
17116
17388
  return { exitCode: 1, summary, warnings, errors };
17117
17389
  }
17118
- const packageJsonPath = path7.join(projectRoot, "package.json");
17119
- if (!fs7.existsSync(packageJsonPath)) {
17390
+ const packageJsonPath = path8.join(projectRoot, "package.json");
17391
+ if (!fs8.existsSync(packageJsonPath)) {
17120
17392
  errors.push("No package.json found. Run this command from a Node.js project root.");
17121
17393
  return { exitCode: 1, summary, warnings, errors };
17122
17394
  }
17123
17395
  const rollbackState = { steps: [] };
17124
17396
  try {
17125
- const instrPath = path7.join(projectRoot, "instrumentation.ts");
17126
- if (fs7.existsSync(instrPath)) {
17127
- rollbackState.originalInstrumentationContent = fs7.readFileSync(instrPath, "utf-8");
17397
+ const instrPath = path8.join(projectRoot, "instrumentation.ts");
17398
+ if (fs8.existsSync(instrPath)) {
17399
+ rollbackState.originalInstrumentationContent = fs8.readFileSync(instrPath, "utf-8");
17128
17400
  }
17129
17401
  const instrResult = await scaffoldInstrumentation(projectRoot);
17130
17402
  switch (instrResult.action) {
@@ -17170,10 +17442,20 @@ async function runInit(options) {
17170
17442
  return { exitCode: 1, summary, warnings, errors };
17171
17443
  }
17172
17444
  try {
17445
+ const envPathForCheck = path8.join(projectRoot, ".env.local");
17446
+ let existingDevKey = false;
17447
+ if (fs8.existsSync(envPathForCheck)) {
17448
+ const existingContent = fs8.readFileSync(envPathForCheck, "utf-8");
17449
+ existingDevKey = isDevApiKey(readEnvLocalApiKey(existingContent));
17450
+ }
17173
17451
  const envCreated = await scaffoldEnvLocal(projectRoot);
17174
17452
  if (envCreated) {
17175
17453
  summary.push("Updated .env.local with Glasstrace configuration");
17176
17454
  rollbackState.steps.push("env-local");
17455
+ } else if (existingDevKey) {
17456
+ summary.push(
17457
+ "Preserved existing .env.local (GLASSTRACE_API_KEY contains a claimed dev key)"
17458
+ );
17177
17459
  } else {
17178
17460
  summary.push("Skipped .env.local (GLASSTRACE_API_KEY already configured)");
17179
17461
  }
@@ -17198,19 +17480,30 @@ async function runInit(options) {
17198
17480
  const ciEnv = process.env["CI"];
17199
17481
  const isCI = typeof ciEnv === "string" && ciEnv.trim() !== "" && ciEnv.toLowerCase() !== "false" && ciEnv.trim() !== "0" || process.env["GITHUB_ACTIONS"] === "true";
17200
17482
  try {
17483
+ const preExistingAnonKey = await readAnonKey(projectRoot);
17201
17484
  const anonKey = await getOrCreateAnonKey(projectRoot);
17485
+ if (preExistingAnonKey !== null) {
17486
+ summary.push("Preserved existing .glasstrace/anon_key");
17487
+ }
17202
17488
  let anyConfigWritten = false;
17203
17489
  if (isCI) {
17204
17490
  const genericAgent = {
17205
17491
  name: "generic",
17206
- mcpConfigPath: path7.join(projectRoot, ".glasstrace", "mcp.json"),
17492
+ mcpConfigPath: path8.join(projectRoot, ".glasstrace", "mcp.json"),
17207
17493
  infoFilePath: null,
17208
17494
  cliAvailable: false,
17209
17495
  registrationCommand: null
17210
17496
  };
17211
17497
  const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
17212
- await writeMcpConfig(genericAgent, genericConfig, projectRoot);
17213
- if (genericAgent.mcpConfigPath !== null && fs7.existsSync(genericAgent.mcpConfigPath)) {
17498
+ const decision = await decideMcpConfigAction({
17499
+ configPath: genericAgent.mcpConfigPath,
17500
+ expectedContent: genericConfig,
17501
+ force: true
17502
+ });
17503
+ if (decision !== "skip") {
17504
+ await writeMcpConfig(genericAgent, genericConfig, projectRoot);
17505
+ }
17506
+ if (genericAgent.mcpConfigPath !== null && fs8.existsSync(genericAgent.mcpConfigPath)) {
17214
17507
  anyConfigWritten = true;
17215
17508
  summary.push("Created .glasstrace/mcp.json (CI mode)");
17216
17509
  }
@@ -17224,14 +17517,14 @@ async function runInit(options) {
17224
17517
  );
17225
17518
  const genericAgent = {
17226
17519
  name: "generic",
17227
- mcpConfigPath: path7.join(projectRoot, ".glasstrace", "mcp.json"),
17520
+ mcpConfigPath: path8.join(projectRoot, ".glasstrace", "mcp.json"),
17228
17521
  infoFilePath: null,
17229
17522
  cliAvailable: false,
17230
17523
  registrationCommand: null
17231
17524
  };
17232
17525
  const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
17233
17526
  await writeMcpConfig(genericAgent, genericConfig, projectRoot);
17234
- if (genericAgent.mcpConfigPath !== null && fs7.existsSync(genericAgent.mcpConfigPath)) {
17527
+ if (genericAgent.mcpConfigPath !== null && fs8.existsSync(genericAgent.mcpConfigPath)) {
17235
17528
  anyConfigWritten = true;
17236
17529
  }
17237
17530
  agents = [];
@@ -17240,8 +17533,22 @@ async function runInit(options) {
17240
17533
  for (const agent of agents) {
17241
17534
  try {
17242
17535
  const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);
17536
+ const decision = await decideMcpConfigAction({
17537
+ configPath: agent.mcpConfigPath,
17538
+ expectedContent: configContent,
17539
+ force: options.force === true || options.yes
17540
+ });
17541
+ if (decision === "skip") {
17542
+ summary.push(
17543
+ `Preserved existing ${agent.mcpConfigPath ?? agent.name} (user declined overwrite)`
17544
+ );
17545
+ if (agent.mcpConfigPath !== null && fs8.existsSync(agent.mcpConfigPath)) {
17546
+ anyConfigWritten = true;
17547
+ }
17548
+ continue;
17549
+ }
17243
17550
  await writeMcpConfig(agent, configContent, projectRoot);
17244
- const configExists = agent.mcpConfigPath !== null && fs7.existsSync(agent.mcpConfigPath);
17551
+ const configExists = agent.mcpConfigPath !== null && fs8.existsSync(agent.mcpConfigPath);
17245
17552
  if (!configExists) {
17246
17553
  continue;
17247
17554
  }
@@ -17311,11 +17618,14 @@ function parseArgs(argv) {
17311
17618
  const args = argv.slice(2);
17312
17619
  let yes = false;
17313
17620
  let coverageMap = false;
17621
+ let force = false;
17314
17622
  for (const arg of args) {
17315
17623
  if (arg === "--yes" || arg === "-y") {
17316
17624
  yes = true;
17317
17625
  } else if (arg === "--coverage-map") {
17318
17626
  coverageMap = true;
17627
+ } else if (arg === "--force") {
17628
+ force = true;
17319
17629
  }
17320
17630
  }
17321
17631
  if (!process.stdin.isTTY) {
@@ -17324,11 +17634,12 @@ function parseArgs(argv) {
17324
17634
  return {
17325
17635
  projectRoot: process.cwd(),
17326
17636
  yes,
17327
- coverageMap
17637
+ coverageMap,
17638
+ force
17328
17639
  };
17329
17640
  }
17330
17641
  var scriptPath = typeof process !== "undefined" && process.argv[1] !== void 0 ? process.argv[1].replace(/\\/g, "/") : void 0;
17331
- var scriptBasename = scriptPath !== void 0 ? path7.basename(scriptPath) : void 0;
17642
+ var scriptBasename = scriptPath !== void 0 ? path8.basename(scriptPath) : void 0;
17332
17643
  var isDirectExecution = scriptPath !== void 0 && (scriptPath.endsWith("/cli/init.js") || scriptPath.endsWith("/cli/init.ts") || scriptBasename === "glasstrace");
17333
17644
  if (isDirectExecution) {
17334
17645
  if (!meetsNodeVersion(20)) {
@@ -17366,47 +17677,78 @@ Usage: glasstrace mcp add [--force] [--dry-run]
17366
17677
  process.exit(1);
17367
17678
  }
17368
17679
  } else if (subcommand === void 0 || subcommand === "init" || subcommand.startsWith("-")) {
17369
- const options = parseArgs(process.argv);
17370
- runInit(options).then((result) => {
17371
- if (result.errors.length > 0) {
17372
- for (const err of result.errors) {
17373
- process.stderr.write(`Error: ${err}
17374
- `);
17375
- }
17680
+ const forwardedArgs = process.argv.slice(subcommand === "init" ? 3 : 2);
17681
+ if (forwardedArgs.includes("--validate")) {
17682
+ let validateProjectRoot = process.cwd();
17683
+ try {
17684
+ validateProjectRoot = resolveProjectRoot(validateProjectRoot).projectRoot;
17685
+ } catch {
17376
17686
  }
17377
- if (result.warnings.length > 0) {
17378
- for (const warn of result.warnings) {
17379
- process.stderr.write(`Warning: ${warn}
17687
+ Promise.resolve().then(() => (init_validate(), validate_exports)).then(({ runValidate: runValidate2 }) => runValidate2({ projectRoot: validateProjectRoot })).then((result) => {
17688
+ for (const line of result.summary) {
17689
+ process.stderr.write(`${line}
17380
17690
  `);
17381
17691
  }
17382
- }
17383
- if (result.summary.length > 0) {
17384
- process.stderr.write("\nGlasstrace initialized successfully!\n\n");
17385
- for (const line of result.summary) {
17386
- process.stderr.write(` - ${line}
17692
+ for (const issue2 of result.issues) {
17693
+ process.stderr.write(` - ${issue2.message}
17694
+ `);
17695
+ if (issue2.fix) {
17696
+ process.stderr.write(` Fix: ${issue2.fix}
17387
17697
  `);
17698
+ }
17388
17699
  }
17389
- process.stderr.write("\nNext steps:\n");
17390
- process.stderr.write(" 1. Start your Next.js dev server\n");
17700
+ process.exit(result.exitCode);
17701
+ }).catch((err) => {
17391
17702
  process.stderr.write(
17392
- " 2. Glasstrace works immediately in anonymous mode\n"
17703
+ `Fatal error: ${err instanceof Error ? err.message : String(err)}
17704
+ `
17393
17705
  );
17706
+ process.exit(1);
17707
+ });
17708
+ } else {
17709
+ const options = parseArgs(process.argv);
17710
+ runInit(options).then((result) => {
17711
+ if (result.errors.length > 0) {
17712
+ for (const err of result.errors) {
17713
+ process.stderr.write(`Error: ${err}
17714
+ `);
17715
+ }
17716
+ }
17717
+ if (result.warnings.length > 0) {
17718
+ for (const warn of result.warnings) {
17719
+ process.stderr.write(`Warning: ${warn}
17720
+ `);
17721
+ }
17722
+ }
17723
+ if (result.summary.length > 0) {
17724
+ process.stderr.write("\nGlasstrace initialized successfully!\n\n");
17725
+ for (const line of result.summary) {
17726
+ process.stderr.write(` - ${line}
17727
+ `);
17728
+ }
17729
+ process.stderr.write("\nNext steps:\n");
17730
+ process.stderr.write(" 1. Start your Next.js dev server\n");
17731
+ process.stderr.write(
17732
+ " 2. Glasstrace works immediately in anonymous mode\n"
17733
+ );
17734
+ process.stderr.write(
17735
+ " 3. To link to your account, set GLASSTRACE_API_KEY in .env.local\n\n"
17736
+ );
17737
+ }
17738
+ process.exit(result.exitCode);
17739
+ }).catch((err) => {
17394
17740
  process.stderr.write(
17395
- " 3. To link to your account, set GLASSTRACE_API_KEY in .env.local\n\n"
17396
- );
17397
- }
17398
- process.exit(result.exitCode);
17399
- }).catch((err) => {
17400
- process.stderr.write(
17401
- `Fatal error: ${err instanceof Error ? err.message : String(err)}
17741
+ `Fatal error: ${err instanceof Error ? err.message : String(err)}
17402
17742
  `
17403
- );
17404
- process.exit(1);
17405
- });
17743
+ );
17744
+ process.exit(1);
17745
+ });
17746
+ }
17406
17747
  } else if (subcommand === "uninit") {
17407
17748
  const remainingArgs = process.argv.slice(3);
17408
17749
  const dryRun = remainingArgs.includes("--dry-run");
17409
- Promise.resolve().then(() => (init_uninit(), uninit_exports)).then(({ runUninit: runUninit2 }) => runUninit2({ projectRoot: process.cwd(), dryRun })).then((result) => {
17750
+ const force = remainingArgs.includes("--force");
17751
+ Promise.resolve().then(() => (init_uninit(), uninit_exports)).then(({ runUninit: runUninit2 }) => runUninit2({ projectRoot: process.cwd(), dryRun, force })).then((result) => {
17410
17752
  if (result.errors.length > 0) {
17411
17753
  for (const err of result.errors) {
17412
17754
  process.stderr.write(`Error: ${err}
@@ -17480,8 +17822,8 @@ Usage: glasstrace mcp add [--force] [--dry-run]
17480
17822
  `Unknown command: ${subcommand}
17481
17823
 
17482
17824
  Usage:
17483
- glasstrace init [--yes] [--coverage-map]
17484
- glasstrace uninit [--dry-run]
17825
+ glasstrace init [--yes] [--coverage-map] [--force] [--validate]
17826
+ glasstrace uninit [--dry-run] [--force]
17485
17827
  glasstrace status [--json]
17486
17828
  glasstrace mcp add [--force] [--dry-run]
17487
17829
  `
@@ -17491,6 +17833,7 @@ Usage:
17491
17833
  }
17492
17834
  // Annotate the CommonJS export names for ESM import in node:
17493
17835
  0 && (module.exports = {
17836
+ decideMcpConfigAction,
17494
17837
  meetsNodeVersion,
17495
17838
  rollbackSteps,
17496
17839
  runInit