@glasstrace/sdk 0.8.0 → 0.9.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-UGHMMOM4.js → chunk-4NDQPWDJ.js} +16 -21
- package/dist/chunk-4NDQPWDJ.js.map +1 -0
- package/dist/chunk-DXRZKKSO.js +21 -0
- package/dist/chunk-DXRZKKSO.js.map +1 -0
- package/dist/{chunk-QW6W4CSA.js → chunk-PQWAKVQ5.js} +9 -4
- package/dist/chunk-PQWAKVQ5.js.map +1 -0
- package/dist/{chunk-SALPGSWK.js → chunk-Y6V7BTF3.js} +2 -2
- package/dist/cli/init.cjs +900 -62
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +295 -15
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +25 -15
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +6 -4
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/uninit.cjs +587 -0
- package/dist/cli/uninit.cjs.map +1 -0
- package/dist/cli/uninit.d.cts +141 -0
- package/dist/cli/uninit.d.ts +141 -0
- package/dist/cli/uninit.js +543 -0
- package/dist/cli/uninit.js.map +1 -0
- package/dist/index.cjs +52 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +46 -39
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-QW6W4CSA.js.map +0 -1
- package/dist/chunk-UGHMMOM4.js.map +0 -1
- /package/dist/{chunk-SALPGSWK.js.map → chunk-Y6V7BTF3.js.map} +0 -0
package/dist/cli/init.cjs
CHANGED
|
@@ -31,6 +31,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
));
|
|
32
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
33
|
|
|
34
|
+
// src/cli/constants.ts
|
|
35
|
+
function formatAgentName(name) {
|
|
36
|
+
const displayNames = {
|
|
37
|
+
claude: "Claude Code",
|
|
38
|
+
codex: "Codex",
|
|
39
|
+
gemini: "Gemini",
|
|
40
|
+
cursor: "Cursor",
|
|
41
|
+
windsurf: "Windsurf",
|
|
42
|
+
generic: "Generic"
|
|
43
|
+
};
|
|
44
|
+
return displayNames[name];
|
|
45
|
+
}
|
|
46
|
+
var MCP_ENDPOINT, NEXT_CONFIG_NAMES;
|
|
47
|
+
var init_constants = __esm({
|
|
48
|
+
"src/cli/constants.ts"() {
|
|
49
|
+
"use strict";
|
|
50
|
+
MCP_ENDPOINT = "https://api.glasstrace.dev/mcp";
|
|
51
|
+
NEXT_CONFIG_NAMES = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
34
55
|
// src/cli/scaffolder.ts
|
|
35
56
|
function identityFingerprint(token) {
|
|
36
57
|
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(token).digest("hex")}`;
|
|
@@ -72,7 +93,7 @@ ${indent}registerGlasstrace();
|
|
|
72
93
|
} else {
|
|
73
94
|
const existingImports = specifiers.trimEnd();
|
|
74
95
|
const separator = existingImports.endsWith(",") ? " " : ", ";
|
|
75
|
-
const updatedImport = `import {${existingImports}${separator}registerGlasstrace} from "@glasstrace/sdk"`;
|
|
96
|
+
const updatedImport = `import { ${existingImports.trim()}${separator}registerGlasstrace } from "@glasstrace/sdk"`;
|
|
76
97
|
modified = content.replace(importMatch[0], updatedImport);
|
|
77
98
|
const newMatch = registerFnRegex.exec(modified);
|
|
78
99
|
if (newMatch) {
|
|
@@ -275,14 +296,14 @@ async function scaffoldMcpMarker(projectRoot, anonKey) {
|
|
|
275
296
|
fs.chmodSync(markerPath, 384);
|
|
276
297
|
return true;
|
|
277
298
|
}
|
|
278
|
-
var import_node_crypto, fs, path
|
|
299
|
+
var import_node_crypto, fs, path;
|
|
279
300
|
var init_scaffolder = __esm({
|
|
280
301
|
"src/cli/scaffolder.ts"() {
|
|
281
302
|
"use strict";
|
|
282
303
|
import_node_crypto = require("crypto");
|
|
283
304
|
fs = __toESM(require("fs"), 1);
|
|
284
305
|
path = __toESM(require("path"), 1);
|
|
285
|
-
|
|
306
|
+
init_constants();
|
|
286
307
|
}
|
|
287
308
|
});
|
|
288
309
|
|
|
@@ -539,10 +560,10 @@ function mergeDefs(...defs) {
|
|
|
539
560
|
function cloneDef(schema) {
|
|
540
561
|
return mergeDefs(schema._zod.def);
|
|
541
562
|
}
|
|
542
|
-
function getElementAtPath(obj,
|
|
543
|
-
if (!
|
|
563
|
+
function getElementAtPath(obj, path7) {
|
|
564
|
+
if (!path7)
|
|
544
565
|
return obj;
|
|
545
|
-
return
|
|
566
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
546
567
|
}
|
|
547
568
|
function promiseAllObject(promisesObj) {
|
|
548
569
|
const keys = Object.keys(promisesObj);
|
|
@@ -854,11 +875,11 @@ function aborted(x, startIndex = 0) {
|
|
|
854
875
|
}
|
|
855
876
|
return false;
|
|
856
877
|
}
|
|
857
|
-
function prefixIssues(
|
|
878
|
+
function prefixIssues(path7, issues) {
|
|
858
879
|
return issues.map((iss) => {
|
|
859
880
|
var _a2;
|
|
860
881
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
861
|
-
iss.path.unshift(
|
|
882
|
+
iss.path.unshift(path7);
|
|
862
883
|
return iss;
|
|
863
884
|
});
|
|
864
885
|
}
|
|
@@ -1101,7 +1122,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1101
1122
|
}
|
|
1102
1123
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
1103
1124
|
const result = { errors: [] };
|
|
1104
|
-
const processError = (error49,
|
|
1125
|
+
const processError = (error49, path7 = []) => {
|
|
1105
1126
|
var _a2, _b;
|
|
1106
1127
|
for (const issue2 of error49.issues) {
|
|
1107
1128
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -1111,7 +1132,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1111
1132
|
} else if (issue2.code === "invalid_element") {
|
|
1112
1133
|
processError({ issues: issue2.issues }, issue2.path);
|
|
1113
1134
|
} else {
|
|
1114
|
-
const fullpath = [...
|
|
1135
|
+
const fullpath = [...path7, ...issue2.path];
|
|
1115
1136
|
if (fullpath.length === 0) {
|
|
1116
1137
|
result.errors.push(mapper(issue2));
|
|
1117
1138
|
continue;
|
|
@@ -1143,8 +1164,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1143
1164
|
}
|
|
1144
1165
|
function toDotPath(_path) {
|
|
1145
1166
|
const segs = [];
|
|
1146
|
-
const
|
|
1147
|
-
for (const seg of
|
|
1167
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1168
|
+
for (const seg of path7) {
|
|
1148
1169
|
if (typeof seg === "number")
|
|
1149
1170
|
segs.push(`[${seg}]`);
|
|
1150
1171
|
else if (typeof seg === "symbol")
|
|
@@ -13908,13 +13929,13 @@ function resolveRef(ref, ctx) {
|
|
|
13908
13929
|
if (!ref.startsWith("#")) {
|
|
13909
13930
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
13910
13931
|
}
|
|
13911
|
-
const
|
|
13912
|
-
if (
|
|
13932
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
13933
|
+
if (path7.length === 0) {
|
|
13913
13934
|
return ctx.rootSchema;
|
|
13914
13935
|
}
|
|
13915
13936
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
13916
|
-
if (
|
|
13917
|
-
const key =
|
|
13937
|
+
if (path7[0] === defsKey) {
|
|
13938
|
+
const key = path7[1];
|
|
13918
13939
|
if (!key || !ctx.defs[key]) {
|
|
13919
13940
|
throw new Error(`Reference not found: ${ref}`);
|
|
13920
13941
|
}
|
|
@@ -14859,9 +14880,14 @@ async function getOrCreateAnonKey(projectRoot) {
|
|
|
14859
14880
|
} catch (err) {
|
|
14860
14881
|
const code = err.code;
|
|
14861
14882
|
if (code === "EEXIST") {
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14883
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
14884
|
+
const winnerKey = await readAnonKey(root);
|
|
14885
|
+
if (winnerKey !== null) {
|
|
14886
|
+
return winnerKey;
|
|
14887
|
+
}
|
|
14888
|
+
if (attempt < 2) {
|
|
14889
|
+
await new Promise((resolve2) => setTimeout(resolve2, 50));
|
|
14890
|
+
}
|
|
14865
14891
|
}
|
|
14866
14892
|
try {
|
|
14867
14893
|
await (0, import_promises.writeFile)(keyPath, newKey, { mode: 384 });
|
|
@@ -14891,9 +14917,9 @@ var init_anon_key = __esm({
|
|
|
14891
14917
|
});
|
|
14892
14918
|
|
|
14893
14919
|
// src/agent-detection/detect.ts
|
|
14894
|
-
async function pathExists(
|
|
14920
|
+
async function pathExists(path7, mode = import_node_fs.constants.R_OK) {
|
|
14895
14921
|
try {
|
|
14896
|
-
await (0, import_promises2.access)(
|
|
14922
|
+
await (0, import_promises2.access)(path7, mode);
|
|
14897
14923
|
return true;
|
|
14898
14924
|
} catch {
|
|
14899
14925
|
return false;
|
|
@@ -15075,7 +15101,7 @@ function generateMcpConfig(agent, endpoint, anonKey) {
|
|
|
15075
15101
|
2
|
|
15076
15102
|
);
|
|
15077
15103
|
case "codex": {
|
|
15078
|
-
const safeEndpoint = endpoint.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
15104
|
+
const safeEndpoint = endpoint.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
15079
15105
|
return [
|
|
15080
15106
|
"[mcp_servers.glasstrace]",
|
|
15081
15107
|
`url = "${safeEndpoint}"`,
|
|
@@ -15143,6 +15169,10 @@ function generateMcpConfig(agent, endpoint, anonKey) {
|
|
|
15143
15169
|
null,
|
|
15144
15170
|
2
|
|
15145
15171
|
);
|
|
15172
|
+
default: {
|
|
15173
|
+
const _exhaustive = agent.name;
|
|
15174
|
+
throw new Error(`Unknown agent: ${_exhaustive}`);
|
|
15175
|
+
}
|
|
15146
15176
|
}
|
|
15147
15177
|
}
|
|
15148
15178
|
function htmlMarkers() {
|
|
@@ -15200,6 +15230,10 @@ ${content}${m.end}
|
|
|
15200
15230
|
case "windsurf":
|
|
15201
15231
|
case "generic":
|
|
15202
15232
|
return "";
|
|
15233
|
+
default: {
|
|
15234
|
+
const _exhaustive = agent.name;
|
|
15235
|
+
throw new Error(`Unknown agent: ${_exhaustive}`);
|
|
15236
|
+
}
|
|
15203
15237
|
}
|
|
15204
15238
|
}
|
|
15205
15239
|
var init_configs = __esm({
|
|
@@ -15391,26 +15425,6 @@ var init_inject = __esm({
|
|
|
15391
15425
|
}
|
|
15392
15426
|
});
|
|
15393
15427
|
|
|
15394
|
-
// src/cli/constants.ts
|
|
15395
|
-
function formatAgentName(name) {
|
|
15396
|
-
const displayNames = {
|
|
15397
|
-
claude: "Claude Code",
|
|
15398
|
-
codex: "Codex",
|
|
15399
|
-
gemini: "Gemini",
|
|
15400
|
-
cursor: "Cursor",
|
|
15401
|
-
windsurf: "Windsurf",
|
|
15402
|
-
generic: "Generic"
|
|
15403
|
-
};
|
|
15404
|
-
return displayNames[name];
|
|
15405
|
-
}
|
|
15406
|
-
var MCP_ENDPOINT;
|
|
15407
|
-
var init_constants = __esm({
|
|
15408
|
-
"src/cli/constants.ts"() {
|
|
15409
|
-
"use strict";
|
|
15410
|
-
MCP_ENDPOINT = "https://api.glasstrace.dev/mcp";
|
|
15411
|
-
}
|
|
15412
|
-
});
|
|
15413
|
-
|
|
15414
15428
|
// src/cli/mcp-add.ts
|
|
15415
15429
|
var mcp_add_exports = {};
|
|
15416
15430
|
__export(mcp_add_exports, {
|
|
@@ -15447,11 +15461,11 @@ async function registerViaCli(agent, anonKey) {
|
|
|
15447
15461
|
MCP_ENDPOINT
|
|
15448
15462
|
]);
|
|
15449
15463
|
const configPath = agent.mcpConfigPath;
|
|
15450
|
-
if (configPath !== null &&
|
|
15451
|
-
const content =
|
|
15464
|
+
if (configPath !== null && fs4.existsSync(configPath)) {
|
|
15465
|
+
const content = fs4.readFileSync(configPath, "utf-8");
|
|
15452
15466
|
if (!content.includes("bearer_token_env_var")) {
|
|
15453
15467
|
const appendContent = content.endsWith("\n") ? "" : "\n";
|
|
15454
|
-
|
|
15468
|
+
fs4.writeFileSync(
|
|
15455
15469
|
configPath,
|
|
15456
15470
|
content + appendContent + 'bearer_token_env_var = "GLASSTRACE_API_KEY"\n',
|
|
15457
15471
|
"utf-8"
|
|
@@ -15496,8 +15510,8 @@ async function mcpAdd(options) {
|
|
|
15496
15510
|
messages: ["Error: Run `glasstrace init` first to generate an API key."]
|
|
15497
15511
|
};
|
|
15498
15512
|
}
|
|
15499
|
-
const markerPath =
|
|
15500
|
-
if (
|
|
15513
|
+
const markerPath = path4.join(projectRoot, ".glasstrace", "mcp-connected");
|
|
15514
|
+
if (fs4.existsSync(markerPath) && !force) {
|
|
15501
15515
|
return {
|
|
15502
15516
|
exitCode: 0,
|
|
15503
15517
|
results: [],
|
|
@@ -15556,7 +15570,7 @@ async function mcpAdd(options) {
|
|
|
15556
15570
|
try {
|
|
15557
15571
|
const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);
|
|
15558
15572
|
await writeMcpConfig(agent, configContent, projectRoot);
|
|
15559
|
-
if (
|
|
15573
|
+
if (fs4.existsSync(agent.mcpConfigPath)) {
|
|
15560
15574
|
const infoContent = generateInfoSection(agent, MCP_ENDPOINT);
|
|
15561
15575
|
if (infoContent !== "") {
|
|
15562
15576
|
await injectInfoSection(agent, infoContent, projectRoot);
|
|
@@ -15623,13 +15637,13 @@ async function mcpAdd(options) {
|
|
|
15623
15637
|
}
|
|
15624
15638
|
return { exitCode: 0, results, messages };
|
|
15625
15639
|
}
|
|
15626
|
-
var import_node_child_process2,
|
|
15640
|
+
var import_node_child_process2, fs4, path4, import_node_util, execFileAsync;
|
|
15627
15641
|
var init_mcp_add = __esm({
|
|
15628
15642
|
"src/cli/mcp-add.ts"() {
|
|
15629
15643
|
"use strict";
|
|
15630
15644
|
import_node_child_process2 = require("child_process");
|
|
15631
|
-
|
|
15632
|
-
|
|
15645
|
+
fs4 = __toESM(require("fs"), 1);
|
|
15646
|
+
path4 = __toESM(require("path"), 1);
|
|
15633
15647
|
import_node_util = require("util");
|
|
15634
15648
|
init_anon_key();
|
|
15635
15649
|
init_detect();
|
|
@@ -15641,6 +15655,552 @@ var init_mcp_add = __esm({
|
|
|
15641
15655
|
}
|
|
15642
15656
|
});
|
|
15643
15657
|
|
|
15658
|
+
// src/cli/uninit.ts
|
|
15659
|
+
var uninit_exports = {};
|
|
15660
|
+
__export(uninit_exports, {
|
|
15661
|
+
findMatchingParen: () => findMatchingParen,
|
|
15662
|
+
isInitCreatedInstrumentation: () => isInitCreatedInstrumentation,
|
|
15663
|
+
processJsonMcpConfig: () => processJsonMcpConfig,
|
|
15664
|
+
processTomlMcpConfig: () => processTomlMcpConfig,
|
|
15665
|
+
removeGlasstraceConfigImport: () => removeGlasstraceConfigImport,
|
|
15666
|
+
removeMarkerSection: () => removeMarkerSection,
|
|
15667
|
+
removeRegisterGlasstrace: () => removeRegisterGlasstrace,
|
|
15668
|
+
runUninit: () => runUninit,
|
|
15669
|
+
unwrapCJSExport: () => unwrapCJSExport,
|
|
15670
|
+
unwrapExport: () => unwrapExport
|
|
15671
|
+
});
|
|
15672
|
+
function findMatchingParen(text, openPos) {
|
|
15673
|
+
let depth = 0;
|
|
15674
|
+
for (let i = openPos; i < text.length; i++) {
|
|
15675
|
+
if (text[i] === "(") {
|
|
15676
|
+
depth++;
|
|
15677
|
+
} else if (text[i] === ")") {
|
|
15678
|
+
depth--;
|
|
15679
|
+
if (depth === 0) {
|
|
15680
|
+
return i;
|
|
15681
|
+
}
|
|
15682
|
+
}
|
|
15683
|
+
}
|
|
15684
|
+
return -1;
|
|
15685
|
+
}
|
|
15686
|
+
function unwrapExport(content) {
|
|
15687
|
+
const pattern = /export\s+default\s+withGlasstraceConfig\s*\(/;
|
|
15688
|
+
const match = pattern.exec(content);
|
|
15689
|
+
if (!match) {
|
|
15690
|
+
return { content, unwrapped: false };
|
|
15691
|
+
}
|
|
15692
|
+
const openParenIdx = match.index + match[0].length - 1;
|
|
15693
|
+
const closeParenIdx = findMatchingParen(content, openParenIdx);
|
|
15694
|
+
if (closeParenIdx === -1) {
|
|
15695
|
+
return { content, unwrapped: false };
|
|
15696
|
+
}
|
|
15697
|
+
const innerExpr = content.slice(openParenIdx + 1, closeParenIdx).trim();
|
|
15698
|
+
if (innerExpr.length === 0) {
|
|
15699
|
+
return { content, unwrapped: false };
|
|
15700
|
+
}
|
|
15701
|
+
const before = content.slice(0, match.index);
|
|
15702
|
+
const afterClose = content.slice(closeParenIdx + 1);
|
|
15703
|
+
const trailing = afterClose.replace(/^;?\s*/, "");
|
|
15704
|
+
const result = before + `export default ${innerExpr};
|
|
15705
|
+
` + trailing;
|
|
15706
|
+
return { content: result, unwrapped: true };
|
|
15707
|
+
}
|
|
15708
|
+
function unwrapCJSExport(content) {
|
|
15709
|
+
const pattern = /module\.exports\s*=\s*withGlasstraceConfig\s*\(/;
|
|
15710
|
+
const match = pattern.exec(content);
|
|
15711
|
+
if (!match) {
|
|
15712
|
+
return { content, unwrapped: false };
|
|
15713
|
+
}
|
|
15714
|
+
const openParenIdx = match.index + match[0].length - 1;
|
|
15715
|
+
const closeParenIdx = findMatchingParen(content, openParenIdx);
|
|
15716
|
+
if (closeParenIdx === -1) {
|
|
15717
|
+
return { content, unwrapped: false };
|
|
15718
|
+
}
|
|
15719
|
+
const innerExpr = content.slice(openParenIdx + 1, closeParenIdx).trim();
|
|
15720
|
+
if (innerExpr.length === 0) {
|
|
15721
|
+
return { content, unwrapped: false };
|
|
15722
|
+
}
|
|
15723
|
+
const before = content.slice(0, match.index);
|
|
15724
|
+
const afterClose = content.slice(closeParenIdx + 1);
|
|
15725
|
+
const trailing = afterClose.replace(/^;?\s*/, "");
|
|
15726
|
+
const result = before + `module.exports = ${innerExpr};
|
|
15727
|
+
` + trailing;
|
|
15728
|
+
return { content: result, unwrapped: true };
|
|
15729
|
+
}
|
|
15730
|
+
function removeGlasstraceConfigImport(content) {
|
|
15731
|
+
const esmSoleImport = /import\s*\{\s*withGlasstraceConfig\s*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/;
|
|
15732
|
+
if (esmSoleImport.test(content)) {
|
|
15733
|
+
return content.replace(esmSoleImport, "");
|
|
15734
|
+
}
|
|
15735
|
+
const esmMultiImport = /import\s*\{([^}]*)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
15736
|
+
const multiMatch = esmMultiImport.exec(content);
|
|
15737
|
+
if (multiMatch) {
|
|
15738
|
+
const specifiers = multiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "withGlasstraceConfig");
|
|
15739
|
+
if (specifiers.length === 0) {
|
|
15740
|
+
return content.replace(
|
|
15741
|
+
/import\s*\{[^}]*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/,
|
|
15742
|
+
""
|
|
15743
|
+
);
|
|
15744
|
+
}
|
|
15745
|
+
const newImport = `import { ${specifiers.join(", ")} } from "@glasstrace/sdk"`;
|
|
15746
|
+
return content.replace(multiMatch[0], newImport);
|
|
15747
|
+
}
|
|
15748
|
+
const cjsSoleRequire = /const\s*\{\s*withGlasstraceConfig\s*\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)\s*;?\s*\n?/;
|
|
15749
|
+
if (cjsSoleRequire.test(content)) {
|
|
15750
|
+
return content.replace(cjsSoleRequire, "");
|
|
15751
|
+
}
|
|
15752
|
+
const cjsMultiRequire = /const\s*\{([^}]*)\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)/;
|
|
15753
|
+
const cjsMultiMatch = cjsMultiRequire.exec(content);
|
|
15754
|
+
if (cjsMultiMatch) {
|
|
15755
|
+
const specifiers = cjsMultiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "withGlasstraceConfig");
|
|
15756
|
+
if (specifiers.length === 0) {
|
|
15757
|
+
return content.replace(
|
|
15758
|
+
/const\s*\{[^}]*\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)\s*;?\s*\n?/,
|
|
15759
|
+
""
|
|
15760
|
+
);
|
|
15761
|
+
}
|
|
15762
|
+
const newRequire = `const { ${specifiers.join(", ")} } = require("@glasstrace/sdk")`;
|
|
15763
|
+
return content.replace(cjsMultiMatch[0], newRequire);
|
|
15764
|
+
}
|
|
15765
|
+
return content;
|
|
15766
|
+
}
|
|
15767
|
+
function cleanLeadingBlankLines(content) {
|
|
15768
|
+
return content.replace(/^\n{2,}/, "\n");
|
|
15769
|
+
}
|
|
15770
|
+
function isInitCreatedInstrumentation(content) {
|
|
15771
|
+
const lines = content.split("\n");
|
|
15772
|
+
const importLines = lines.filter(
|
|
15773
|
+
(l) => /^\s*import\s/.test(l) && !l.trim().startsWith("//")
|
|
15774
|
+
);
|
|
15775
|
+
const nonGlasstraceImports = importLines.filter(
|
|
15776
|
+
(l) => !l.includes("@glasstrace/sdk")
|
|
15777
|
+
);
|
|
15778
|
+
if (nonGlasstraceImports.length > 0) {
|
|
15779
|
+
return false;
|
|
15780
|
+
}
|
|
15781
|
+
const registerFnRegex = /export\s+(?:async\s+)?function\s+register\s*\([^)]*\)\s*\{/;
|
|
15782
|
+
const match = registerFnRegex.exec(content);
|
|
15783
|
+
if (!match) {
|
|
15784
|
+
return false;
|
|
15785
|
+
}
|
|
15786
|
+
const afterBrace = content.slice(match.index + match[0].length);
|
|
15787
|
+
const closingBraceIdx = findMatchingBrace(content, match.index + match[0].length - 1);
|
|
15788
|
+
if (closingBraceIdx === -1) {
|
|
15789
|
+
return false;
|
|
15790
|
+
}
|
|
15791
|
+
const body = afterBrace.slice(0, closingBraceIdx - (match.index + match[0].length));
|
|
15792
|
+
const bodyLines = body.split("\n");
|
|
15793
|
+
const statements = bodyLines.filter((l) => {
|
|
15794
|
+
const trimmed = l.trim();
|
|
15795
|
+
return trimmed !== "" && !trimmed.startsWith("//");
|
|
15796
|
+
});
|
|
15797
|
+
if (statements.length !== 1) {
|
|
15798
|
+
return false;
|
|
15799
|
+
}
|
|
15800
|
+
if (!/^\s*registerGlasstrace\s*\(\s*\)\s*;?\s*$/.test(statements[0])) {
|
|
15801
|
+
return false;
|
|
15802
|
+
}
|
|
15803
|
+
const beforeFn = content.slice(0, match.index);
|
|
15804
|
+
const afterFn = content.slice(closingBraceIdx + 1);
|
|
15805
|
+
const topLevelBefore = beforeFn.split("\n").filter((l) => {
|
|
15806
|
+
const trimmed = l.trim();
|
|
15807
|
+
return trimmed !== "" && !trimmed.startsWith("//") && !trimmed.startsWith("import ") && !trimmed.startsWith("import{");
|
|
15808
|
+
});
|
|
15809
|
+
const topLevelAfter = afterFn.split("\n").filter((l) => {
|
|
15810
|
+
const trimmed = l.trim();
|
|
15811
|
+
return trimmed !== "" && !trimmed.startsWith("//");
|
|
15812
|
+
});
|
|
15813
|
+
return topLevelBefore.length === 0 && topLevelAfter.length === 0;
|
|
15814
|
+
}
|
|
15815
|
+
function findMatchingBrace(text, openPos) {
|
|
15816
|
+
let depth = 0;
|
|
15817
|
+
for (let i = openPos; i < text.length; i++) {
|
|
15818
|
+
if (text[i] === "{") {
|
|
15819
|
+
depth++;
|
|
15820
|
+
} else if (text[i] === "}") {
|
|
15821
|
+
depth--;
|
|
15822
|
+
if (depth === 0) {
|
|
15823
|
+
return i;
|
|
15824
|
+
}
|
|
15825
|
+
}
|
|
15826
|
+
}
|
|
15827
|
+
return -1;
|
|
15828
|
+
}
|
|
15829
|
+
function removeRegisterGlasstrace(content) {
|
|
15830
|
+
let result = content;
|
|
15831
|
+
result = result.replace(
|
|
15832
|
+
/[ \t]*\/\/\s*Glasstrace must be registered[^\n]*\n(?:[ \t]*\/\/[^\n]*\n)*[ \t]*registerGlasstrace\s*\(\s*\)\s*;?\s*\n?/g,
|
|
15833
|
+
""
|
|
15834
|
+
);
|
|
15835
|
+
result = result.replace(
|
|
15836
|
+
/[ \t]*registerGlasstrace\s*\(\s*\)\s*;?\s*\n?/g,
|
|
15837
|
+
""
|
|
15838
|
+
);
|
|
15839
|
+
const soleImportPattern = /import\s*\{\s*registerGlasstrace\s*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/;
|
|
15840
|
+
if (soleImportPattern.test(result)) {
|
|
15841
|
+
result = result.replace(soleImportPattern, "");
|
|
15842
|
+
} else {
|
|
15843
|
+
const multiImportPattern = /import\s*\{([^}]*)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
15844
|
+
const multiMatch = multiImportPattern.exec(result);
|
|
15845
|
+
if (multiMatch) {
|
|
15846
|
+
const specifiers = multiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "registerGlasstrace");
|
|
15847
|
+
if (specifiers.length === 0) {
|
|
15848
|
+
result = result.replace(
|
|
15849
|
+
/import\s*\{[^}]*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/,
|
|
15850
|
+
""
|
|
15851
|
+
);
|
|
15852
|
+
} else {
|
|
15853
|
+
const newImport = `import { ${specifiers.join(", ")} } from "@glasstrace/sdk"`;
|
|
15854
|
+
result = result.replace(multiMatch[0], newImport);
|
|
15855
|
+
}
|
|
15856
|
+
}
|
|
15857
|
+
}
|
|
15858
|
+
return cleanLeadingBlankLines(result);
|
|
15859
|
+
}
|
|
15860
|
+
function removeMarkerSection(content) {
|
|
15861
|
+
const lines = content.split("\n");
|
|
15862
|
+
let startIdx = -1;
|
|
15863
|
+
let endIdx = -1;
|
|
15864
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15865
|
+
const trimmed = lines[i].trim();
|
|
15866
|
+
if (trimmed === "<!-- glasstrace:mcp:start -->" || trimmed === "# glasstrace:mcp:start") {
|
|
15867
|
+
startIdx = i;
|
|
15868
|
+
} else if ((trimmed === "<!-- glasstrace:mcp:end -->" || trimmed === "# glasstrace:mcp:end") && startIdx !== -1) {
|
|
15869
|
+
endIdx = i;
|
|
15870
|
+
break;
|
|
15871
|
+
}
|
|
15872
|
+
}
|
|
15873
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
15874
|
+
return { content, removed: false };
|
|
15875
|
+
}
|
|
15876
|
+
const before = lines.slice(0, startIdx);
|
|
15877
|
+
const after = lines.slice(endIdx + 1);
|
|
15878
|
+
while (before.length > 0 && before[before.length - 1].trim() === "") {
|
|
15879
|
+
before.pop();
|
|
15880
|
+
}
|
|
15881
|
+
const result = [...before, ...after].join("\n");
|
|
15882
|
+
const trimmedResult = result.trimEnd();
|
|
15883
|
+
return {
|
|
15884
|
+
content: trimmedResult.length > 0 ? trimmedResult + "\n" : "",
|
|
15885
|
+
removed: true
|
|
15886
|
+
};
|
|
15887
|
+
}
|
|
15888
|
+
function processJsonMcpConfig(content) {
|
|
15889
|
+
let parsed;
|
|
15890
|
+
try {
|
|
15891
|
+
parsed = JSON.parse(content);
|
|
15892
|
+
} catch {
|
|
15893
|
+
return { action: "skipped" };
|
|
15894
|
+
}
|
|
15895
|
+
const mcpServers = parsed["mcpServers"];
|
|
15896
|
+
if (!mcpServers || typeof mcpServers !== "object" || !("glasstrace" in mcpServers)) {
|
|
15897
|
+
return { action: "skipped" };
|
|
15898
|
+
}
|
|
15899
|
+
const remainingServers = Object.keys(mcpServers).filter((k) => k !== "glasstrace");
|
|
15900
|
+
const otherTopLevelKeys = Object.keys(parsed).filter((k) => k !== "mcpServers");
|
|
15901
|
+
if (remainingServers.length === 0 && otherTopLevelKeys.length === 0) {
|
|
15902
|
+
return { action: "deleted" };
|
|
15903
|
+
}
|
|
15904
|
+
const { glasstrace: _, ...rest } = mcpServers;
|
|
15905
|
+
void _;
|
|
15906
|
+
if (remainingServers.length > 0) {
|
|
15907
|
+
parsed["mcpServers"] = rest;
|
|
15908
|
+
} else {
|
|
15909
|
+
delete parsed["mcpServers"];
|
|
15910
|
+
}
|
|
15911
|
+
return { action: "removed-key", content: JSON.stringify(parsed, null, 2) + "\n" };
|
|
15912
|
+
}
|
|
15913
|
+
function processTomlMcpConfig(content) {
|
|
15914
|
+
if (!content.includes("[mcp_servers.glasstrace]")) {
|
|
15915
|
+
return { action: "skipped" };
|
|
15916
|
+
}
|
|
15917
|
+
const lines = content.split("\n");
|
|
15918
|
+
const startIdx = lines.findIndex(
|
|
15919
|
+
(l) => l.trim() === "[mcp_servers.glasstrace]"
|
|
15920
|
+
);
|
|
15921
|
+
if (startIdx === -1) {
|
|
15922
|
+
return { action: "skipped" };
|
|
15923
|
+
}
|
|
15924
|
+
let endIdx = lines.length;
|
|
15925
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
15926
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
15927
|
+
endIdx = i;
|
|
15928
|
+
break;
|
|
15929
|
+
}
|
|
15930
|
+
}
|
|
15931
|
+
const before = lines.slice(0, startIdx);
|
|
15932
|
+
const after = lines.slice(endIdx);
|
|
15933
|
+
while (before.length > 0 && before[before.length - 1].trim() === "") {
|
|
15934
|
+
before.pop();
|
|
15935
|
+
}
|
|
15936
|
+
const result = [...before, ...after].join("\n").trimEnd();
|
|
15937
|
+
if (result.trim().length === 0) {
|
|
15938
|
+
return { action: "deleted" };
|
|
15939
|
+
}
|
|
15940
|
+
return { action: "removed-section", content: result + "\n" };
|
|
15941
|
+
}
|
|
15942
|
+
async function runUninit(options) {
|
|
15943
|
+
const { projectRoot, dryRun } = options;
|
|
15944
|
+
const summary = [];
|
|
15945
|
+
const warnings = [];
|
|
15946
|
+
const errors = [];
|
|
15947
|
+
const prefix = dryRun ? "[dry run] " : "";
|
|
15948
|
+
try {
|
|
15949
|
+
let configHandled = false;
|
|
15950
|
+
for (const name of NEXT_CONFIG_NAMES) {
|
|
15951
|
+
const configPath = path5.join(projectRoot, name);
|
|
15952
|
+
if (!fs5.existsSync(configPath)) {
|
|
15953
|
+
continue;
|
|
15954
|
+
}
|
|
15955
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
15956
|
+
if (!content.includes("withGlasstraceConfig")) {
|
|
15957
|
+
continue;
|
|
15958
|
+
}
|
|
15959
|
+
const isESM = name.endsWith(".ts") || name.endsWith(".mjs");
|
|
15960
|
+
const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
|
|
15961
|
+
if (unwrapResult.unwrapped) {
|
|
15962
|
+
const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
|
|
15963
|
+
const final = cleanLeadingBlankLines(cleaned);
|
|
15964
|
+
if (!dryRun) {
|
|
15965
|
+
fs5.writeFileSync(configPath, final, "utf-8");
|
|
15966
|
+
}
|
|
15967
|
+
summary.push(`${prefix}Unwrapped withGlasstraceConfig from ${name}`);
|
|
15968
|
+
configHandled = true;
|
|
15969
|
+
break;
|
|
15970
|
+
} else {
|
|
15971
|
+
warnings.push(
|
|
15972
|
+
`${name} contains withGlasstraceConfig but could not be automatically unwrapped. Please remove withGlasstraceConfig() manually.`
|
|
15973
|
+
);
|
|
15974
|
+
configHandled = true;
|
|
15975
|
+
break;
|
|
15976
|
+
}
|
|
15977
|
+
}
|
|
15978
|
+
if (!configHandled) {
|
|
15979
|
+
}
|
|
15980
|
+
} catch (err) {
|
|
15981
|
+
errors.push(
|
|
15982
|
+
`Failed to process next.config: ${err instanceof Error ? err.message : String(err)}`
|
|
15983
|
+
);
|
|
15984
|
+
}
|
|
15985
|
+
try {
|
|
15986
|
+
const instrPath = path5.join(projectRoot, "instrumentation.ts");
|
|
15987
|
+
if (fs5.existsSync(instrPath)) {
|
|
15988
|
+
const content = fs5.readFileSync(instrPath, "utf-8");
|
|
15989
|
+
if (content.includes("registerGlasstrace") || content.includes("@glasstrace/sdk")) {
|
|
15990
|
+
if (isInitCreatedInstrumentation(content)) {
|
|
15991
|
+
if (!dryRun) {
|
|
15992
|
+
fs5.unlinkSync(instrPath);
|
|
15993
|
+
}
|
|
15994
|
+
summary.push(`${prefix}Deleted instrumentation.ts (init-created)`);
|
|
15995
|
+
} else {
|
|
15996
|
+
const cleaned = removeRegisterGlasstrace(content);
|
|
15997
|
+
if (cleaned !== content) {
|
|
15998
|
+
if (!dryRun) {
|
|
15999
|
+
fs5.writeFileSync(instrPath, cleaned, "utf-8");
|
|
16000
|
+
}
|
|
16001
|
+
summary.push(
|
|
16002
|
+
`${prefix}Removed registerGlasstrace() from instrumentation.ts`
|
|
16003
|
+
);
|
|
16004
|
+
}
|
|
16005
|
+
}
|
|
16006
|
+
}
|
|
16007
|
+
}
|
|
16008
|
+
} catch (err) {
|
|
16009
|
+
errors.push(
|
|
16010
|
+
`Failed to process instrumentation.ts: ${err instanceof Error ? err.message : String(err)}`
|
|
16011
|
+
);
|
|
16012
|
+
}
|
|
16013
|
+
try {
|
|
16014
|
+
const glasstraceDir = path5.join(projectRoot, ".glasstrace");
|
|
16015
|
+
if (fs5.existsSync(glasstraceDir)) {
|
|
16016
|
+
if (!dryRun) {
|
|
16017
|
+
fs5.rmSync(glasstraceDir, { recursive: true, force: true });
|
|
16018
|
+
}
|
|
16019
|
+
summary.push(`${prefix}Removed .glasstrace/ directory`);
|
|
16020
|
+
}
|
|
16021
|
+
} catch (err) {
|
|
16022
|
+
errors.push(
|
|
16023
|
+
`Failed to remove .glasstrace/: ${err instanceof Error ? err.message : String(err)}`
|
|
16024
|
+
);
|
|
16025
|
+
}
|
|
16026
|
+
try {
|
|
16027
|
+
const envPath = path5.join(projectRoot, ".env.local");
|
|
16028
|
+
if (fs5.existsSync(envPath)) {
|
|
16029
|
+
const content = fs5.readFileSync(envPath, "utf-8");
|
|
16030
|
+
const lines = content.split("\n");
|
|
16031
|
+
const filtered = lines.filter((line) => {
|
|
16032
|
+
const trimmed = line.trim();
|
|
16033
|
+
return !(/^\s*#?\s*GLASSTRACE_API_KEY\s*=/.test(trimmed) || /^\s*#?\s*GLASSTRACE_COVERAGE_MAP\s*=/.test(trimmed));
|
|
16034
|
+
});
|
|
16035
|
+
if (filtered.length !== lines.length) {
|
|
16036
|
+
const result = filtered.join("\n");
|
|
16037
|
+
if (result.trim().length === 0) {
|
|
16038
|
+
if (!dryRun) {
|
|
16039
|
+
fs5.unlinkSync(envPath);
|
|
16040
|
+
}
|
|
16041
|
+
summary.push(`${prefix}Deleted .env.local (no remaining entries)`);
|
|
16042
|
+
} else {
|
|
16043
|
+
if (!dryRun) {
|
|
16044
|
+
fs5.writeFileSync(envPath, result, "utf-8");
|
|
16045
|
+
}
|
|
16046
|
+
summary.push(`${prefix}Removed GLASSTRACE entries from .env.local`);
|
|
16047
|
+
}
|
|
16048
|
+
}
|
|
16049
|
+
}
|
|
16050
|
+
} catch (err) {
|
|
16051
|
+
errors.push(
|
|
16052
|
+
`Failed to process .env.local: ${err instanceof Error ? err.message : String(err)}`
|
|
16053
|
+
);
|
|
16054
|
+
}
|
|
16055
|
+
try {
|
|
16056
|
+
const gitignorePath = path5.join(projectRoot, ".gitignore");
|
|
16057
|
+
if (fs5.existsSync(gitignorePath)) {
|
|
16058
|
+
const content = fs5.readFileSync(gitignorePath, "utf-8");
|
|
16059
|
+
const lines = content.split("\n");
|
|
16060
|
+
const mcpGitignoreEntries = /* @__PURE__ */ new Set([
|
|
16061
|
+
".glasstrace/",
|
|
16062
|
+
".mcp.json",
|
|
16063
|
+
".cursor/mcp.json",
|
|
16064
|
+
".gemini/settings.json",
|
|
16065
|
+
".codex/config.toml"
|
|
16066
|
+
]);
|
|
16067
|
+
const filtered = lines.filter(
|
|
16068
|
+
(line) => !mcpGitignoreEntries.has(line.trim())
|
|
16069
|
+
);
|
|
16070
|
+
if (filtered.length !== lines.length) {
|
|
16071
|
+
const result = filtered.join("\n");
|
|
16072
|
+
if (result.trim().length === 0) {
|
|
16073
|
+
if (!dryRun) {
|
|
16074
|
+
fs5.unlinkSync(gitignorePath);
|
|
16075
|
+
}
|
|
16076
|
+
summary.push(`${prefix}Deleted .gitignore (no remaining entries)`);
|
|
16077
|
+
} else {
|
|
16078
|
+
if (!dryRun) {
|
|
16079
|
+
fs5.writeFileSync(gitignorePath, result, "utf-8");
|
|
16080
|
+
}
|
|
16081
|
+
summary.push(`${prefix}Removed Glasstrace entries from .gitignore`);
|
|
16082
|
+
}
|
|
16083
|
+
}
|
|
16084
|
+
}
|
|
16085
|
+
} catch (err) {
|
|
16086
|
+
errors.push(
|
|
16087
|
+
`Failed to process .gitignore: ${err instanceof Error ? err.message : String(err)}`
|
|
16088
|
+
);
|
|
16089
|
+
}
|
|
16090
|
+
try {
|
|
16091
|
+
for (const configFile of MCP_CONFIG_FILES) {
|
|
16092
|
+
const configPath = path5.join(projectRoot, configFile);
|
|
16093
|
+
if (!fs5.existsSync(configPath)) {
|
|
16094
|
+
continue;
|
|
16095
|
+
}
|
|
16096
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
16097
|
+
const result = processJsonMcpConfig(content);
|
|
16098
|
+
if (result.action === "deleted") {
|
|
16099
|
+
if (!dryRun) {
|
|
16100
|
+
fs5.unlinkSync(configPath);
|
|
16101
|
+
}
|
|
16102
|
+
summary.push(`${prefix}Deleted ${configFile}`);
|
|
16103
|
+
} else if (result.action === "removed-key" && result.content !== void 0) {
|
|
16104
|
+
if (!dryRun) {
|
|
16105
|
+
fs5.writeFileSync(configPath, result.content, "utf-8");
|
|
16106
|
+
}
|
|
16107
|
+
summary.push(`${prefix}Removed glasstrace from ${configFile}`);
|
|
16108
|
+
}
|
|
16109
|
+
}
|
|
16110
|
+
const codexConfigPath = path5.join(projectRoot, ".codex", "config.toml");
|
|
16111
|
+
if (fs5.existsSync(codexConfigPath)) {
|
|
16112
|
+
const content = fs5.readFileSync(codexConfigPath, "utf-8");
|
|
16113
|
+
const tomlResult = processTomlMcpConfig(content);
|
|
16114
|
+
if (tomlResult.action === "deleted") {
|
|
16115
|
+
if (!dryRun) {
|
|
16116
|
+
fs5.unlinkSync(codexConfigPath);
|
|
16117
|
+
}
|
|
16118
|
+
summary.push(`${prefix}Deleted .codex/config.toml`);
|
|
16119
|
+
} else if (tomlResult.action === "removed-section" && tomlResult.content !== void 0) {
|
|
16120
|
+
if (!dryRun) {
|
|
16121
|
+
fs5.writeFileSync(codexConfigPath, tomlResult.content, "utf-8");
|
|
16122
|
+
}
|
|
16123
|
+
summary.push(`${prefix}Removed glasstrace from .codex/config.toml`);
|
|
16124
|
+
}
|
|
16125
|
+
}
|
|
16126
|
+
const hasWindsurfMarkers = fs5.existsSync(path5.join(projectRoot, ".windsurfrules")) || fs5.existsSync(path5.join(projectRoot, ".windsurf"));
|
|
16127
|
+
if (hasWindsurfMarkers) {
|
|
16128
|
+
const windsurfConfigPath = path5.join(
|
|
16129
|
+
os.homedir(),
|
|
16130
|
+
".codeium",
|
|
16131
|
+
"windsurf",
|
|
16132
|
+
"mcp_config.json"
|
|
16133
|
+
);
|
|
16134
|
+
if (fs5.existsSync(windsurfConfigPath)) {
|
|
16135
|
+
const content = fs5.readFileSync(windsurfConfigPath, "utf-8");
|
|
16136
|
+
const windsurfResult = processJsonMcpConfig(content);
|
|
16137
|
+
if (windsurfResult.action === "deleted") {
|
|
16138
|
+
if (!dryRun) {
|
|
16139
|
+
fs5.unlinkSync(windsurfConfigPath);
|
|
16140
|
+
}
|
|
16141
|
+
summary.push(`${prefix}Deleted Windsurf MCP config`);
|
|
16142
|
+
} else if (windsurfResult.action === "removed-key" && windsurfResult.content !== void 0) {
|
|
16143
|
+
if (!dryRun) {
|
|
16144
|
+
fs5.writeFileSync(windsurfConfigPath, windsurfResult.content, "utf-8");
|
|
16145
|
+
}
|
|
16146
|
+
summary.push(`${prefix}Removed glasstrace from Windsurf MCP config`);
|
|
16147
|
+
}
|
|
16148
|
+
}
|
|
16149
|
+
}
|
|
16150
|
+
} catch (err) {
|
|
16151
|
+
errors.push(
|
|
16152
|
+
`Failed to process MCP config: ${err instanceof Error ? err.message : String(err)}`
|
|
16153
|
+
);
|
|
16154
|
+
}
|
|
16155
|
+
try {
|
|
16156
|
+
for (const infoFile of AGENT_INFO_FILES) {
|
|
16157
|
+
const filePath = path5.join(projectRoot, infoFile);
|
|
16158
|
+
if (!fs5.existsSync(filePath)) {
|
|
16159
|
+
continue;
|
|
16160
|
+
}
|
|
16161
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
16162
|
+
const result = removeMarkerSection(content);
|
|
16163
|
+
if (result.removed) {
|
|
16164
|
+
if (result.content.trim().length === 0) {
|
|
16165
|
+
if (!dryRun) {
|
|
16166
|
+
fs5.unlinkSync(filePath);
|
|
16167
|
+
}
|
|
16168
|
+
summary.push(`${prefix}Deleted ${infoFile} (only contained Glasstrace section)`);
|
|
16169
|
+
} else {
|
|
16170
|
+
if (!dryRun) {
|
|
16171
|
+
fs5.writeFileSync(filePath, result.content, "utf-8");
|
|
16172
|
+
}
|
|
16173
|
+
summary.push(`${prefix}Removed Glasstrace section from ${infoFile}`);
|
|
16174
|
+
}
|
|
16175
|
+
}
|
|
16176
|
+
}
|
|
16177
|
+
} catch (err) {
|
|
16178
|
+
errors.push(
|
|
16179
|
+
`Failed to process agent info files: ${err instanceof Error ? err.message : String(err)}`
|
|
16180
|
+
);
|
|
16181
|
+
}
|
|
16182
|
+
if (summary.length === 0 && errors.length === 0) {
|
|
16183
|
+
summary.push("No Glasstrace artifacts found \u2014 nothing to do.");
|
|
16184
|
+
}
|
|
16185
|
+
return { exitCode: errors.length > 0 ? 1 : 0, summary, warnings, errors };
|
|
16186
|
+
}
|
|
16187
|
+
var fs5, os, path5, MCP_CONFIG_FILES, AGENT_INFO_FILES;
|
|
16188
|
+
var init_uninit = __esm({
|
|
16189
|
+
"src/cli/uninit.ts"() {
|
|
16190
|
+
"use strict";
|
|
16191
|
+
fs5 = __toESM(require("fs"), 1);
|
|
16192
|
+
os = __toESM(require("os"), 1);
|
|
16193
|
+
path5 = __toESM(require("path"), 1);
|
|
16194
|
+
init_constants();
|
|
16195
|
+
MCP_CONFIG_FILES = [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json"];
|
|
16196
|
+
AGENT_INFO_FILES = [
|
|
16197
|
+
"CLAUDE.md",
|
|
16198
|
+
"codex.md",
|
|
16199
|
+
".cursorrules"
|
|
16200
|
+
];
|
|
16201
|
+
}
|
|
16202
|
+
});
|
|
16203
|
+
|
|
15644
16204
|
// src/cli/init.ts
|
|
15645
16205
|
var init_exports = {};
|
|
15646
16206
|
__export(init_exports, {
|
|
@@ -15648,8 +16208,8 @@ __export(init_exports, {
|
|
|
15648
16208
|
runInit: () => runInit
|
|
15649
16209
|
});
|
|
15650
16210
|
module.exports = __toCommonJS(init_exports);
|
|
15651
|
-
var
|
|
15652
|
-
var
|
|
16211
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
16212
|
+
var path6 = __toESM(require("path"), 1);
|
|
15653
16213
|
var readline = __toESM(require("readline"), 1);
|
|
15654
16214
|
init_scaffolder();
|
|
15655
16215
|
|
|
@@ -15828,6 +16388,240 @@ init_detect();
|
|
|
15828
16388
|
init_configs();
|
|
15829
16389
|
init_inject();
|
|
15830
16390
|
init_constants();
|
|
16391
|
+
|
|
16392
|
+
// src/cli/monorepo.ts
|
|
16393
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
16394
|
+
var path3 = __toESM(require("path"), 1);
|
|
16395
|
+
init_constants();
|
|
16396
|
+
function resolveProjectRoot(cwd) {
|
|
16397
|
+
if (hasNextConfig(cwd)) {
|
|
16398
|
+
return { projectRoot: cwd, isMonorepo: false };
|
|
16399
|
+
}
|
|
16400
|
+
if (hasNextDependency(cwd)) {
|
|
16401
|
+
return { projectRoot: cwd, isMonorepo: false };
|
|
16402
|
+
}
|
|
16403
|
+
if (isMonorepoRoot(cwd)) {
|
|
16404
|
+
const apps = findNextJsApps(cwd);
|
|
16405
|
+
if (apps.length === 0) {
|
|
16406
|
+
throw new Error(
|
|
16407
|
+
"This is a monorepo but no Next.js apps were found in workspace packages."
|
|
16408
|
+
);
|
|
16409
|
+
}
|
|
16410
|
+
if (apps.length === 1) {
|
|
16411
|
+
const appDir = apps[0];
|
|
16412
|
+
const relativePath = path3.relative(cwd, appDir);
|
|
16413
|
+
return {
|
|
16414
|
+
projectRoot: appDir,
|
|
16415
|
+
isMonorepo: true,
|
|
16416
|
+
appRelativePath: relativePath
|
|
16417
|
+
};
|
|
16418
|
+
}
|
|
16419
|
+
const appList = apps.map((app) => ` - ${path3.relative(cwd, app)}`).join("\n");
|
|
16420
|
+
throw new Error(
|
|
16421
|
+
`Found multiple Next.js apps:
|
|
16422
|
+
${appList}
|
|
16423
|
+
Run init from the specific app directory you want to instrument.`
|
|
16424
|
+
);
|
|
16425
|
+
}
|
|
16426
|
+
throw new Error(
|
|
16427
|
+
"No Next.js project found in the current directory.\nRun this command from your Next.js app directory, or from a monorepo root."
|
|
16428
|
+
);
|
|
16429
|
+
}
|
|
16430
|
+
function hasNextConfig(dir) {
|
|
16431
|
+
return NEXT_CONFIG_NAMES.some(
|
|
16432
|
+
(name) => fs3.existsSync(path3.join(dir, name))
|
|
16433
|
+
);
|
|
16434
|
+
}
|
|
16435
|
+
function hasNextDependency(dir) {
|
|
16436
|
+
const packageJsonPath = path3.join(dir, "package.json");
|
|
16437
|
+
if (!fs3.existsSync(packageJsonPath)) return false;
|
|
16438
|
+
try {
|
|
16439
|
+
const content = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
16440
|
+
const pkg = JSON.parse(content);
|
|
16441
|
+
const deps = pkg["dependencies"];
|
|
16442
|
+
const devDeps = pkg["devDependencies"];
|
|
16443
|
+
if (typeof deps === "object" && deps !== null && "next" in deps) return true;
|
|
16444
|
+
if (typeof devDeps === "object" && devDeps !== null && "next" in devDeps) return true;
|
|
16445
|
+
} catch {
|
|
16446
|
+
}
|
|
16447
|
+
return false;
|
|
16448
|
+
}
|
|
16449
|
+
function isMonorepoRoot(dir) {
|
|
16450
|
+
if (fs3.existsSync(path3.join(dir, "pnpm-workspace.yaml"))) return true;
|
|
16451
|
+
if (fs3.existsSync(path3.join(dir, "turbo.json"))) return true;
|
|
16452
|
+
if (fs3.existsSync(path3.join(dir, "lerna.json"))) return true;
|
|
16453
|
+
const packageJsonPath = path3.join(dir, "package.json");
|
|
16454
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
16455
|
+
try {
|
|
16456
|
+
const content = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
16457
|
+
const pkg = JSON.parse(content);
|
|
16458
|
+
if (pkg["workspaces"] !== void 0) return true;
|
|
16459
|
+
} catch {
|
|
16460
|
+
}
|
|
16461
|
+
}
|
|
16462
|
+
return false;
|
|
16463
|
+
}
|
|
16464
|
+
function findNextJsApps(monorepoRoot) {
|
|
16465
|
+
const { includeGlobs, negationPatterns } = collectWorkspaceGlobs(monorepoRoot);
|
|
16466
|
+
if (includeGlobs.length === 0) {
|
|
16467
|
+
throw new Error(
|
|
16468
|
+
'Monorepo detected but no workspace configuration found.\nAdd a "workspaces" field to package.json or create pnpm-workspace.yaml.'
|
|
16469
|
+
);
|
|
16470
|
+
}
|
|
16471
|
+
const workspaceDirs = expandGlobs(monorepoRoot, includeGlobs);
|
|
16472
|
+
const excludedDirs = expandGlobs(monorepoRoot, negationPatterns);
|
|
16473
|
+
const excludedSet = new Set(excludedDirs);
|
|
16474
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16475
|
+
const nextApps = [];
|
|
16476
|
+
for (const dir of workspaceDirs) {
|
|
16477
|
+
if (seen.has(dir)) continue;
|
|
16478
|
+
seen.add(dir);
|
|
16479
|
+
if (excludedSet.has(dir)) continue;
|
|
16480
|
+
if (hasNextConfig(dir) || hasNextDependency(dir)) {
|
|
16481
|
+
nextApps.push(dir);
|
|
16482
|
+
}
|
|
16483
|
+
}
|
|
16484
|
+
return nextApps.sort();
|
|
16485
|
+
}
|
|
16486
|
+
function collectWorkspaceGlobs(root) {
|
|
16487
|
+
const globs = [];
|
|
16488
|
+
const negations = [];
|
|
16489
|
+
const pnpmPath = path3.join(root, "pnpm-workspace.yaml");
|
|
16490
|
+
if (fs3.existsSync(pnpmPath)) {
|
|
16491
|
+
const content = fs3.readFileSync(pnpmPath, "utf-8");
|
|
16492
|
+
const parsed = parsePnpmWorkspaceYaml(content);
|
|
16493
|
+
globs.push(...parsed.includeGlobs);
|
|
16494
|
+
negations.push(...parsed.negationPatterns);
|
|
16495
|
+
}
|
|
16496
|
+
const packageJsonPath = path3.join(root, "package.json");
|
|
16497
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
16498
|
+
try {
|
|
16499
|
+
const content = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
16500
|
+
const pkg = JSON.parse(content);
|
|
16501
|
+
globs.push(...parsePackageJsonWorkspaces(pkg));
|
|
16502
|
+
} catch {
|
|
16503
|
+
}
|
|
16504
|
+
}
|
|
16505
|
+
const lernaPath = path3.join(root, "lerna.json");
|
|
16506
|
+
if (fs3.existsSync(lernaPath)) {
|
|
16507
|
+
try {
|
|
16508
|
+
const content = fs3.readFileSync(lernaPath, "utf-8");
|
|
16509
|
+
const lerna = JSON.parse(content);
|
|
16510
|
+
const packages = lerna["packages"];
|
|
16511
|
+
if (Array.isArray(packages)) {
|
|
16512
|
+
for (const pkg of packages) {
|
|
16513
|
+
if (typeof pkg === "string") {
|
|
16514
|
+
globs.push(pkg);
|
|
16515
|
+
}
|
|
16516
|
+
}
|
|
16517
|
+
}
|
|
16518
|
+
} catch {
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
return {
|
|
16522
|
+
includeGlobs: [...new Set(globs)],
|
|
16523
|
+
negationPatterns: [...new Set(negations)]
|
|
16524
|
+
};
|
|
16525
|
+
}
|
|
16526
|
+
function parsePnpmWorkspaceYaml(content) {
|
|
16527
|
+
const lines = content.split("\n");
|
|
16528
|
+
const includeGlobs = [];
|
|
16529
|
+
const negationPatterns = [];
|
|
16530
|
+
let inPackages = false;
|
|
16531
|
+
for (const rawLine of lines) {
|
|
16532
|
+
const trimmed = rawLine.trim();
|
|
16533
|
+
if (/^packages\s*:/.test(trimmed)) {
|
|
16534
|
+
inPackages = true;
|
|
16535
|
+
continue;
|
|
16536
|
+
}
|
|
16537
|
+
if (inPackages && trimmed.length > 0 && !trimmed.startsWith("-") && !rawLine.startsWith(" ") && !rawLine.startsWith(" ")) {
|
|
16538
|
+
inPackages = false;
|
|
16539
|
+
continue;
|
|
16540
|
+
}
|
|
16541
|
+
if (!inPackages) continue;
|
|
16542
|
+
const itemMatch = /^\s*-\s+(.+)$/.exec(rawLine);
|
|
16543
|
+
if (!itemMatch) continue;
|
|
16544
|
+
const value = itemMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
16545
|
+
if (value.length === 0) continue;
|
|
16546
|
+
if (value.startsWith("!")) {
|
|
16547
|
+
negationPatterns.push(value.slice(1));
|
|
16548
|
+
continue;
|
|
16549
|
+
}
|
|
16550
|
+
includeGlobs.push(value);
|
|
16551
|
+
}
|
|
16552
|
+
return { includeGlobs, negationPatterns };
|
|
16553
|
+
}
|
|
16554
|
+
function parsePackageJsonWorkspaces(pkg) {
|
|
16555
|
+
const workspaces = pkg["workspaces"];
|
|
16556
|
+
if (workspaces === void 0 || workspaces === null) return [];
|
|
16557
|
+
if (Array.isArray(workspaces)) {
|
|
16558
|
+
return workspaces.filter((w) => typeof w === "string");
|
|
16559
|
+
}
|
|
16560
|
+
if (typeof workspaces === "object") {
|
|
16561
|
+
const obj = workspaces;
|
|
16562
|
+
const packages = obj["packages"];
|
|
16563
|
+
if (Array.isArray(packages)) {
|
|
16564
|
+
return packages.filter((p) => typeof p === "string");
|
|
16565
|
+
}
|
|
16566
|
+
}
|
|
16567
|
+
return [];
|
|
16568
|
+
}
|
|
16569
|
+
function expandGlobs(root, globs) {
|
|
16570
|
+
const dirs = [];
|
|
16571
|
+
for (const glob of globs) {
|
|
16572
|
+
const cleanGlob = glob.replace(/\/+$/, "");
|
|
16573
|
+
if (cleanGlob.includes("**")) {
|
|
16574
|
+
const prefix = cleanGlob.split("**")[0].replace(/\/+$/, "");
|
|
16575
|
+
const baseDir = path3.join(root, prefix);
|
|
16576
|
+
if (fs3.existsSync(baseDir)) {
|
|
16577
|
+
dirs.push(...walkDirectories(baseDir));
|
|
16578
|
+
}
|
|
16579
|
+
} else if (cleanGlob.includes("*")) {
|
|
16580
|
+
const parts = cleanGlob.split("*");
|
|
16581
|
+
const baseDir = path3.join(root, parts[0].replace(/\/+$/, ""));
|
|
16582
|
+
const suffix = parts.slice(1).join("*");
|
|
16583
|
+
if (!fs3.existsSync(baseDir)) continue;
|
|
16584
|
+
let entries;
|
|
16585
|
+
try {
|
|
16586
|
+
entries = fs3.readdirSync(baseDir, { withFileTypes: true });
|
|
16587
|
+
} catch {
|
|
16588
|
+
continue;
|
|
16589
|
+
}
|
|
16590
|
+
for (const entry of entries) {
|
|
16591
|
+
if (!entry.isDirectory()) continue;
|
|
16592
|
+
if (suffix && !entry.name.endsWith(suffix)) continue;
|
|
16593
|
+
dirs.push(path3.join(baseDir, entry.name));
|
|
16594
|
+
}
|
|
16595
|
+
} else {
|
|
16596
|
+
const targetDir = path3.join(root, cleanGlob);
|
|
16597
|
+
if (fs3.existsSync(targetDir) && fs3.statSync(targetDir).isDirectory()) {
|
|
16598
|
+
dirs.push(targetDir);
|
|
16599
|
+
}
|
|
16600
|
+
}
|
|
16601
|
+
}
|
|
16602
|
+
return dirs;
|
|
16603
|
+
}
|
|
16604
|
+
function walkDirectories(baseDir) {
|
|
16605
|
+
const result = [];
|
|
16606
|
+
let entries;
|
|
16607
|
+
try {
|
|
16608
|
+
entries = fs3.readdirSync(baseDir, { withFileTypes: true });
|
|
16609
|
+
} catch {
|
|
16610
|
+
return result;
|
|
16611
|
+
}
|
|
16612
|
+
for (const entry of entries) {
|
|
16613
|
+
if (!entry.isDirectory()) continue;
|
|
16614
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
16615
|
+
const fullPath = path3.join(baseDir, entry.name);
|
|
16616
|
+
if (fs3.existsSync(path3.join(fullPath, "package.json"))) {
|
|
16617
|
+
result.push(fullPath);
|
|
16618
|
+
}
|
|
16619
|
+
result.push(...walkDirectories(fullPath));
|
|
16620
|
+
}
|
|
16621
|
+
return result;
|
|
16622
|
+
}
|
|
16623
|
+
|
|
16624
|
+
// src/cli/init.ts
|
|
15831
16625
|
function meetsNodeVersion(minMajor) {
|
|
15832
16626
|
const [major] = process.versions.node.split(".").map(Number);
|
|
15833
16627
|
return major >= minMajor;
|
|
@@ -15854,12 +16648,23 @@ async function promptYesNo(question, defaultValue) {
|
|
|
15854
16648
|
});
|
|
15855
16649
|
}
|
|
15856
16650
|
async function runInit(options) {
|
|
15857
|
-
const {
|
|
16651
|
+
const { yes, coverageMap } = options;
|
|
15858
16652
|
const summary = [];
|
|
15859
16653
|
const warnings = [];
|
|
15860
16654
|
const errors = [];
|
|
15861
|
-
|
|
15862
|
-
|
|
16655
|
+
let projectRoot;
|
|
16656
|
+
try {
|
|
16657
|
+
const classification = resolveProjectRoot(options.projectRoot);
|
|
16658
|
+
projectRoot = classification.projectRoot;
|
|
16659
|
+
if (classification.isMonorepo && classification.appRelativePath) {
|
|
16660
|
+
summary.push(`Found Next.js app at ${classification.appRelativePath} \u2014 installing there`);
|
|
16661
|
+
}
|
|
16662
|
+
} catch (err) {
|
|
16663
|
+
errors.push(err instanceof Error ? err.message : String(err));
|
|
16664
|
+
return { exitCode: 1, summary, warnings, errors };
|
|
16665
|
+
}
|
|
16666
|
+
const packageJsonPath = path6.join(projectRoot, "package.json");
|
|
16667
|
+
if (!fs6.existsSync(packageJsonPath)) {
|
|
15863
16668
|
errors.push("No package.json found. Run this command from a Node.js project root.");
|
|
15864
16669
|
return { exitCode: 1, summary, warnings, errors };
|
|
15865
16670
|
}
|
|
@@ -15932,14 +16737,14 @@ async function runInit(options) {
|
|
|
15932
16737
|
if (isCI) {
|
|
15933
16738
|
const genericAgent = {
|
|
15934
16739
|
name: "generic",
|
|
15935
|
-
mcpConfigPath:
|
|
16740
|
+
mcpConfigPath: path6.join(projectRoot, ".glasstrace", "mcp.json"),
|
|
15936
16741
|
infoFilePath: null,
|
|
15937
16742
|
cliAvailable: false,
|
|
15938
16743
|
registrationCommand: null
|
|
15939
16744
|
};
|
|
15940
16745
|
const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
|
|
15941
16746
|
await writeMcpConfig(genericAgent, genericConfig, projectRoot);
|
|
15942
|
-
if (genericAgent.mcpConfigPath !== null &&
|
|
16747
|
+
if (genericAgent.mcpConfigPath !== null && fs6.existsSync(genericAgent.mcpConfigPath)) {
|
|
15943
16748
|
anyConfigWritten = true;
|
|
15944
16749
|
summary.push("Created .glasstrace/mcp.json (CI mode)");
|
|
15945
16750
|
}
|
|
@@ -15953,14 +16758,14 @@ async function runInit(options) {
|
|
|
15953
16758
|
);
|
|
15954
16759
|
const genericAgent = {
|
|
15955
16760
|
name: "generic",
|
|
15956
|
-
mcpConfigPath:
|
|
16761
|
+
mcpConfigPath: path6.join(projectRoot, ".glasstrace", "mcp.json"),
|
|
15957
16762
|
infoFilePath: null,
|
|
15958
16763
|
cliAvailable: false,
|
|
15959
16764
|
registrationCommand: null
|
|
15960
16765
|
};
|
|
15961
16766
|
const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
|
|
15962
16767
|
await writeMcpConfig(genericAgent, genericConfig, projectRoot);
|
|
15963
|
-
if (genericAgent.mcpConfigPath !== null &&
|
|
16768
|
+
if (genericAgent.mcpConfigPath !== null && fs6.existsSync(genericAgent.mcpConfigPath)) {
|
|
15964
16769
|
anyConfigWritten = true;
|
|
15965
16770
|
}
|
|
15966
16771
|
agents = [];
|
|
@@ -15970,7 +16775,7 @@ async function runInit(options) {
|
|
|
15970
16775
|
try {
|
|
15971
16776
|
const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);
|
|
15972
16777
|
await writeMcpConfig(agent, configContent, projectRoot);
|
|
15973
|
-
const configExists = agent.mcpConfigPath !== null &&
|
|
16778
|
+
const configExists = agent.mcpConfigPath !== null && fs6.existsSync(agent.mcpConfigPath);
|
|
15974
16779
|
if (!configExists) {
|
|
15975
16780
|
continue;
|
|
15976
16781
|
}
|
|
@@ -16057,7 +16862,7 @@ function parseArgs(argv) {
|
|
|
16057
16862
|
};
|
|
16058
16863
|
}
|
|
16059
16864
|
var scriptPath = typeof process !== "undefined" && process.argv[1] !== void 0 ? process.argv[1].replace(/\\/g, "/") : void 0;
|
|
16060
|
-
var scriptBasename = scriptPath !== void 0 ?
|
|
16865
|
+
var scriptBasename = scriptPath !== void 0 ? path6.basename(scriptPath) : void 0;
|
|
16061
16866
|
var isDirectExecution = scriptPath !== void 0 && (scriptPath.endsWith("/cli/init.js") || scriptPath.endsWith("/cli/init.ts") || scriptBasename === "glasstrace");
|
|
16062
16867
|
if (isDirectExecution) {
|
|
16063
16868
|
if (!meetsNodeVersion(20)) {
|
|
@@ -16128,6 +16933,38 @@ Usage: glasstrace mcp add [--force] [--dry-run]
|
|
|
16128
16933
|
}).catch((err) => {
|
|
16129
16934
|
process.stderr.write(
|
|
16130
16935
|
`Fatal error: ${err instanceof Error ? err.message : String(err)}
|
|
16936
|
+
`
|
|
16937
|
+
);
|
|
16938
|
+
process.exit(1);
|
|
16939
|
+
});
|
|
16940
|
+
} else if (subcommand === "uninit") {
|
|
16941
|
+
const remainingArgs = process.argv.slice(3);
|
|
16942
|
+
const dryRun = remainingArgs.includes("--dry-run");
|
|
16943
|
+
Promise.resolve().then(() => (init_uninit(), uninit_exports)).then(({ runUninit: runUninit2 }) => runUninit2({ projectRoot: process.cwd(), dryRun })).then((result) => {
|
|
16944
|
+
if (result.errors.length > 0) {
|
|
16945
|
+
for (const err of result.errors) {
|
|
16946
|
+
process.stderr.write(`Error: ${err}
|
|
16947
|
+
`);
|
|
16948
|
+
}
|
|
16949
|
+
}
|
|
16950
|
+
if (result.warnings.length > 0) {
|
|
16951
|
+
for (const warn of result.warnings) {
|
|
16952
|
+
process.stderr.write(`Warning: ${warn}
|
|
16953
|
+
`);
|
|
16954
|
+
}
|
|
16955
|
+
}
|
|
16956
|
+
if (result.summary.length > 0) {
|
|
16957
|
+
process.stderr.write("\n");
|
|
16958
|
+
for (const line of result.summary) {
|
|
16959
|
+
process.stderr.write(` ${line}
|
|
16960
|
+
`);
|
|
16961
|
+
}
|
|
16962
|
+
process.stderr.write("\n");
|
|
16963
|
+
}
|
|
16964
|
+
process.exit(result.exitCode);
|
|
16965
|
+
}).catch((err) => {
|
|
16966
|
+
process.stderr.write(
|
|
16967
|
+
`Fatal error: ${err instanceof Error ? err.message : String(err)}
|
|
16131
16968
|
`
|
|
16132
16969
|
);
|
|
16133
16970
|
process.exit(1);
|
|
@@ -16138,6 +16975,7 @@ Usage: glasstrace mcp add [--force] [--dry-run]
|
|
|
16138
16975
|
|
|
16139
16976
|
Usage:
|
|
16140
16977
|
glasstrace init [--yes] [--coverage-map]
|
|
16978
|
+
glasstrace uninit [--dry-run]
|
|
16141
16979
|
glasstrace mcp add [--force] [--dry-run]
|
|
16142
16980
|
`
|
|
16143
16981
|
);
|