@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.
- package/dist/{chunk-ERGEG4ZQ.js → chunk-2LDBR3F3.js} +16 -3
- package/dist/chunk-2LDBR3F3.js.map +1 -0
- package/dist/chunk-A2AZL6MZ.js +309 -0
- package/dist/chunk-A2AZL6MZ.js.map +1 -0
- package/dist/{chunk-ARAOZCZT.js → chunk-ROFOJQWN.js} +118 -16
- package/dist/chunk-ROFOJQWN.js.map +1 -0
- package/dist/{chunk-WV3NIPWJ.js → chunk-ZNOD6FC7.js} +18 -276
- package/dist/chunk-ZNOD6FC7.js.map +1 -0
- package/dist/cli/init.cjs +458 -115
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +33 -1
- package/dist/cli/init.d.ts +33 -1
- package/dist/cli/init.js +144 -42
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +4 -2
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/uninit.cjs +181 -60
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.d.cts +38 -8
- package/dist/cli/uninit.d.ts +38 -8
- package/dist/cli/uninit.js +6 -3
- package/dist/cli/validate.cjs +135 -0
- package/dist/cli/validate.cjs.map +1 -0
- package/dist/cli/validate.d.cts +60 -0
- package/dist/cli/validate.d.ts +60 -0
- package/dist/cli/validate.js +103 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/index.cjs +123 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -5
- package/dist/index.d.ts +45 -5
- package/dist/index.js +109 -46
- package/dist/index.js.map +1 -1
- package/dist/{source-map-uploader-W6VPGY26.js → source-map-uploader-3GWUQDTS.js} +6 -2
- package/package.json +6 -4
- package/dist/chunk-ARAOZCZT.js.map +0 -1
- package/dist/chunk-ERGEG4ZQ.js.map +0 -1
- package/dist/chunk-WV3NIPWJ.js.map +0 -1
- /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
|
|
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 (
|
|
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,
|
|
574
|
-
if (!
|
|
614
|
+
function getElementAtPath(obj, path9) {
|
|
615
|
+
if (!path9)
|
|
575
616
|
return obj;
|
|
576
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 = [...
|
|
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
|
|
1179
|
-
for (const seg of
|
|
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
|
|
14014
|
-
if (
|
|
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 (
|
|
14019
|
-
const key =
|
|
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 [
|
|
14979
|
+
const [fs9, path9] = await Promise.all([
|
|
14939
14980
|
import("fs/promises"),
|
|
14940
14981
|
import("path")
|
|
14941
14982
|
]);
|
|
14942
|
-
fsPathCache = { fs:
|
|
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(
|
|
15071
|
+
async function pathExists(path9, mode = import_node_fs.constants.R_OK) {
|
|
15031
15072
|
try {
|
|
15032
|
-
await (0, import_promises.access)(
|
|
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
|
|
16191
|
-
const
|
|
16192
|
-
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
|
|
16197
|
-
if (
|
|
16198
|
-
|
|
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
|
-
|
|
16204
|
-
|
|
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 =
|
|
16623
|
-
const content =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
16721
|
-
const content =
|
|
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
|
|
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
|
-
|
|
16776
|
-
|
|
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
|
|
16807
|
-
var
|
|
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 =
|
|
17023
|
-
if (
|
|
17024
|
-
const content =
|
|
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
|
-
|
|
17298
|
+
fs8.unlinkSync(instrPath);
|
|
17027
17299
|
} else if (state?.originalInstrumentationContent !== void 0) {
|
|
17028
|
-
|
|
17300
|
+
fs8.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
|
|
17029
17301
|
} else {
|
|
17030
17302
|
const cleaned = removeRegisterGlasstrace(content);
|
|
17031
17303
|
if (cleaned !== content) {
|
|
17032
|
-
|
|
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 =
|
|
17041
|
-
if (!
|
|
17312
|
+
const configPath = path8.join(projectRoot, name);
|
|
17313
|
+
if (!fs8.existsSync(configPath)) {
|
|
17042
17314
|
continue;
|
|
17043
17315
|
}
|
|
17044
|
-
const content =
|
|
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
|
-
|
|
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 =
|
|
17060
|
-
if (
|
|
17061
|
-
const content =
|
|
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
|
-
|
|
17342
|
+
fs8.unlinkSync(envPath);
|
|
17071
17343
|
} else {
|
|
17072
|
-
|
|
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 =
|
|
17080
|
-
if (
|
|
17081
|
-
const content =
|
|
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
|
-
|
|
17361
|
+
fs8.unlinkSync(gitignorePath);
|
|
17090
17362
|
} else {
|
|
17091
|
-
|
|
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 =
|
|
17119
|
-
if (!
|
|
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 =
|
|
17126
|
-
if (
|
|
17127
|
-
rollbackState.originalInstrumentationContent =
|
|
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:
|
|
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
|
|
17213
|
-
|
|
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:
|
|
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 &&
|
|
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 &&
|
|
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 ?
|
|
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
|
|
17370
|
-
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
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
|
-
|
|
17378
|
-
for (const
|
|
17379
|
-
process.stderr.write(
|
|
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
|
-
|
|
17384
|
-
|
|
17385
|
-
|
|
17386
|
-
|
|
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.
|
|
17390
|
-
|
|
17700
|
+
process.exit(result.exitCode);
|
|
17701
|
+
}).catch((err) => {
|
|
17391
17702
|
process.stderr.write(
|
|
17392
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|