@glasstrace/sdk 0.7.3 → 0.9.0
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-CKK6VKKC.js → chunk-UGHMMOM4.js} +75 -8
- package/dist/chunk-UGHMMOM4.js.map +1 -0
- package/dist/cli/init.cjs +949 -58
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +305 -27
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +1 -1
- package/dist/cli/uninit.cjs +583 -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 +541 -0
- package/dist/cli/uninit.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-CKK6VKKC.js.map +0 -1
package/dist/cli/init.cjs
CHANGED
|
@@ -35,12 +35,68 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
35
35
|
function identityFingerprint(token) {
|
|
36
36
|
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(token).digest("hex")}`;
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return
|
|
38
|
+
function hasRegisterGlasstraceCall(content) {
|
|
39
|
+
return content.split("\n").some((line) => {
|
|
40
|
+
const uncommented = line.replace(/\/\/.*$/, "");
|
|
41
|
+
return /\bregisterGlasstrace\s*\(/.test(uncommented);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function injectRegisterGlasstrace(content) {
|
|
45
|
+
if (hasRegisterGlasstraceCall(content)) {
|
|
46
|
+
return { injected: false, content };
|
|
47
|
+
}
|
|
48
|
+
const registerFnRegex = /export\s+(?:async\s+)?function\s+register\s*\([^)]*\)\s*\{/;
|
|
49
|
+
const match = registerFnRegex.exec(content);
|
|
50
|
+
if (!match) {
|
|
51
|
+
return { injected: false, content };
|
|
52
|
+
}
|
|
53
|
+
const afterBrace = content.slice(match.index + match[0].length);
|
|
54
|
+
const indentMatch = /\n([ \t]+)/.exec(afterBrace);
|
|
55
|
+
const indent = indentMatch ? indentMatch[1] : " ";
|
|
56
|
+
const importLine = 'import { registerGlasstrace } from "@glasstrace/sdk";\n';
|
|
57
|
+
const hasGlasstraceImport = content.includes("@glasstrace/sdk");
|
|
58
|
+
const insertPoint = match.index + match[0].length;
|
|
59
|
+
const callInjection = `
|
|
60
|
+
${indent}// Glasstrace must be registered before other instrumentation
|
|
61
|
+
${indent}registerGlasstrace();
|
|
62
|
+
`;
|
|
63
|
+
let modified;
|
|
64
|
+
if (hasGlasstraceImport) {
|
|
65
|
+
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
66
|
+
const importMatch = importRegex.exec(content);
|
|
67
|
+
if (importMatch) {
|
|
68
|
+
const specifiers = importMatch[1];
|
|
69
|
+
const alreadyImported = specifiers.split(",").some((s) => s.trim() === "registerGlasstrace");
|
|
70
|
+
if (alreadyImported) {
|
|
71
|
+
modified = content.slice(0, insertPoint) + callInjection + content.slice(insertPoint);
|
|
72
|
+
} else {
|
|
73
|
+
const existingImports = specifiers.trimEnd();
|
|
74
|
+
const separator = existingImports.endsWith(",") ? " " : ", ";
|
|
75
|
+
const updatedImport = `import {${existingImports}${separator}registerGlasstrace} from "@glasstrace/sdk"`;
|
|
76
|
+
modified = content.replace(importMatch[0], updatedImport);
|
|
77
|
+
const newMatch = registerFnRegex.exec(modified);
|
|
78
|
+
if (newMatch) {
|
|
79
|
+
const newInsertPoint = newMatch.index + newMatch[0].length;
|
|
80
|
+
modified = modified.slice(0, newInsertPoint) + callInjection + modified.slice(newInsertPoint);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
modified = importLine + content;
|
|
85
|
+
const newMatch = registerFnRegex.exec(modified);
|
|
86
|
+
if (newMatch) {
|
|
87
|
+
const newInsertPoint = newMatch.index + newMatch[0].length;
|
|
88
|
+
modified = modified.slice(0, newInsertPoint) + callInjection + modified.slice(newInsertPoint);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
modified = importLine + content.slice(0, insertPoint) + callInjection + content.slice(insertPoint);
|
|
42
93
|
}
|
|
43
|
-
|
|
94
|
+
return { injected: true, content: modified };
|
|
95
|
+
}
|
|
96
|
+
async function scaffoldInstrumentation(projectRoot) {
|
|
97
|
+
const filePath = path.join(projectRoot, "instrumentation.ts");
|
|
98
|
+
if (!fs.existsSync(filePath)) {
|
|
99
|
+
const content = `import { registerGlasstrace } from "@glasstrace/sdk";
|
|
44
100
|
|
|
45
101
|
export async function register() {
|
|
46
102
|
// Glasstrace must be registered before Prisma instrumentation
|
|
@@ -49,8 +105,19 @@ export async function register() {
|
|
|
49
105
|
registerGlasstrace();
|
|
50
106
|
}
|
|
51
107
|
`;
|
|
52
|
-
|
|
53
|
-
|
|
108
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
109
|
+
return { action: "created" };
|
|
110
|
+
}
|
|
111
|
+
const existing = fs.readFileSync(filePath, "utf-8");
|
|
112
|
+
if (hasRegisterGlasstraceCall(existing)) {
|
|
113
|
+
return { action: "already-registered" };
|
|
114
|
+
}
|
|
115
|
+
const result = injectRegisterGlasstrace(existing);
|
|
116
|
+
if (result.injected) {
|
|
117
|
+
fs.writeFileSync(filePath, result.content, "utf-8");
|
|
118
|
+
return { action: "injected" };
|
|
119
|
+
}
|
|
120
|
+
return { action: "unrecognized" };
|
|
54
121
|
}
|
|
55
122
|
async function scaffoldNextConfig(projectRoot) {
|
|
56
123
|
let configPath;
|
|
@@ -472,10 +539,10 @@ function mergeDefs(...defs) {
|
|
|
472
539
|
function cloneDef(schema) {
|
|
473
540
|
return mergeDefs(schema._zod.def);
|
|
474
541
|
}
|
|
475
|
-
function getElementAtPath(obj,
|
|
476
|
-
if (!
|
|
542
|
+
function getElementAtPath(obj, path7) {
|
|
543
|
+
if (!path7)
|
|
477
544
|
return obj;
|
|
478
|
-
return
|
|
545
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
479
546
|
}
|
|
480
547
|
function promiseAllObject(promisesObj) {
|
|
481
548
|
const keys = Object.keys(promisesObj);
|
|
@@ -787,11 +854,11 @@ function aborted(x, startIndex = 0) {
|
|
|
787
854
|
}
|
|
788
855
|
return false;
|
|
789
856
|
}
|
|
790
|
-
function prefixIssues(
|
|
857
|
+
function prefixIssues(path7, issues) {
|
|
791
858
|
return issues.map((iss) => {
|
|
792
859
|
var _a2;
|
|
793
860
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
794
|
-
iss.path.unshift(
|
|
861
|
+
iss.path.unshift(path7);
|
|
795
862
|
return iss;
|
|
796
863
|
});
|
|
797
864
|
}
|
|
@@ -1034,7 +1101,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1034
1101
|
}
|
|
1035
1102
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
1036
1103
|
const result = { errors: [] };
|
|
1037
|
-
const processError = (error49,
|
|
1104
|
+
const processError = (error49, path7 = []) => {
|
|
1038
1105
|
var _a2, _b;
|
|
1039
1106
|
for (const issue2 of error49.issues) {
|
|
1040
1107
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -1044,7 +1111,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1044
1111
|
} else if (issue2.code === "invalid_element") {
|
|
1045
1112
|
processError({ issues: issue2.issues }, issue2.path);
|
|
1046
1113
|
} else {
|
|
1047
|
-
const fullpath = [...
|
|
1114
|
+
const fullpath = [...path7, ...issue2.path];
|
|
1048
1115
|
if (fullpath.length === 0) {
|
|
1049
1116
|
result.errors.push(mapper(issue2));
|
|
1050
1117
|
continue;
|
|
@@ -1076,8 +1143,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1076
1143
|
}
|
|
1077
1144
|
function toDotPath(_path) {
|
|
1078
1145
|
const segs = [];
|
|
1079
|
-
const
|
|
1080
|
-
for (const seg of
|
|
1146
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1147
|
+
for (const seg of path7) {
|
|
1081
1148
|
if (typeof seg === "number")
|
|
1082
1149
|
segs.push(`[${seg}]`);
|
|
1083
1150
|
else if (typeof seg === "symbol")
|
|
@@ -13841,13 +13908,13 @@ function resolveRef(ref, ctx) {
|
|
|
13841
13908
|
if (!ref.startsWith("#")) {
|
|
13842
13909
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
13843
13910
|
}
|
|
13844
|
-
const
|
|
13845
|
-
if (
|
|
13911
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
13912
|
+
if (path7.length === 0) {
|
|
13846
13913
|
return ctx.rootSchema;
|
|
13847
13914
|
}
|
|
13848
13915
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
13849
|
-
if (
|
|
13850
|
-
const key =
|
|
13916
|
+
if (path7[0] === defsKey) {
|
|
13917
|
+
const key = path7[1];
|
|
13851
13918
|
if (!key || !ctx.defs[key]) {
|
|
13852
13919
|
throw new Error(`Reference not found: ${ref}`);
|
|
13853
13920
|
}
|
|
@@ -14824,9 +14891,9 @@ var init_anon_key = __esm({
|
|
|
14824
14891
|
});
|
|
14825
14892
|
|
|
14826
14893
|
// src/agent-detection/detect.ts
|
|
14827
|
-
async function pathExists(
|
|
14894
|
+
async function pathExists(path7, mode = import_node_fs.constants.R_OK) {
|
|
14828
14895
|
try {
|
|
14829
|
-
await (0, import_promises2.access)(
|
|
14896
|
+
await (0, import_promises2.access)(path7, mode);
|
|
14830
14897
|
return true;
|
|
14831
14898
|
} catch {
|
|
14832
14899
|
return false;
|
|
@@ -15380,11 +15447,11 @@ async function registerViaCli(agent, anonKey) {
|
|
|
15380
15447
|
MCP_ENDPOINT
|
|
15381
15448
|
]);
|
|
15382
15449
|
const configPath = agent.mcpConfigPath;
|
|
15383
|
-
if (configPath !== null &&
|
|
15384
|
-
const content =
|
|
15450
|
+
if (configPath !== null && fs4.existsSync(configPath)) {
|
|
15451
|
+
const content = fs4.readFileSync(configPath, "utf-8");
|
|
15385
15452
|
if (!content.includes("bearer_token_env_var")) {
|
|
15386
15453
|
const appendContent = content.endsWith("\n") ? "" : "\n";
|
|
15387
|
-
|
|
15454
|
+
fs4.writeFileSync(
|
|
15388
15455
|
configPath,
|
|
15389
15456
|
content + appendContent + 'bearer_token_env_var = "GLASSTRACE_API_KEY"\n',
|
|
15390
15457
|
"utf-8"
|
|
@@ -15429,8 +15496,8 @@ async function mcpAdd(options) {
|
|
|
15429
15496
|
messages: ["Error: Run `glasstrace init` first to generate an API key."]
|
|
15430
15497
|
};
|
|
15431
15498
|
}
|
|
15432
|
-
const markerPath =
|
|
15433
|
-
if (
|
|
15499
|
+
const markerPath = path4.join(projectRoot, ".glasstrace", "mcp-connected");
|
|
15500
|
+
if (fs4.existsSync(markerPath) && !force) {
|
|
15434
15501
|
return {
|
|
15435
15502
|
exitCode: 0,
|
|
15436
15503
|
results: [],
|
|
@@ -15489,7 +15556,7 @@ async function mcpAdd(options) {
|
|
|
15489
15556
|
try {
|
|
15490
15557
|
const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);
|
|
15491
15558
|
await writeMcpConfig(agent, configContent, projectRoot);
|
|
15492
|
-
if (
|
|
15559
|
+
if (fs4.existsSync(agent.mcpConfigPath)) {
|
|
15493
15560
|
const infoContent = generateInfoSection(agent, MCP_ENDPOINT);
|
|
15494
15561
|
if (infoContent !== "") {
|
|
15495
15562
|
await injectInfoSection(agent, infoContent, projectRoot);
|
|
@@ -15556,13 +15623,13 @@ async function mcpAdd(options) {
|
|
|
15556
15623
|
}
|
|
15557
15624
|
return { exitCode: 0, results, messages };
|
|
15558
15625
|
}
|
|
15559
|
-
var import_node_child_process2,
|
|
15626
|
+
var import_node_child_process2, fs4, path4, import_node_util, execFileAsync;
|
|
15560
15627
|
var init_mcp_add = __esm({
|
|
15561
15628
|
"src/cli/mcp-add.ts"() {
|
|
15562
15629
|
"use strict";
|
|
15563
15630
|
import_node_child_process2 = require("child_process");
|
|
15564
|
-
|
|
15565
|
-
|
|
15631
|
+
fs4 = __toESM(require("fs"), 1);
|
|
15632
|
+
path4 = __toESM(require("path"), 1);
|
|
15566
15633
|
import_node_util = require("util");
|
|
15567
15634
|
init_anon_key();
|
|
15568
15635
|
init_detect();
|
|
@@ -15574,6 +15641,552 @@ var init_mcp_add = __esm({
|
|
|
15574
15641
|
}
|
|
15575
15642
|
});
|
|
15576
15643
|
|
|
15644
|
+
// src/cli/uninit.ts
|
|
15645
|
+
var uninit_exports = {};
|
|
15646
|
+
__export(uninit_exports, {
|
|
15647
|
+
findMatchingParen: () => findMatchingParen,
|
|
15648
|
+
isInitCreatedInstrumentation: () => isInitCreatedInstrumentation,
|
|
15649
|
+
processJsonMcpConfig: () => processJsonMcpConfig,
|
|
15650
|
+
processTomlMcpConfig: () => processTomlMcpConfig,
|
|
15651
|
+
removeGlasstraceConfigImport: () => removeGlasstraceConfigImport,
|
|
15652
|
+
removeMarkerSection: () => removeMarkerSection,
|
|
15653
|
+
removeRegisterGlasstrace: () => removeRegisterGlasstrace,
|
|
15654
|
+
runUninit: () => runUninit,
|
|
15655
|
+
unwrapCJSExport: () => unwrapCJSExport,
|
|
15656
|
+
unwrapExport: () => unwrapExport
|
|
15657
|
+
});
|
|
15658
|
+
function findMatchingParen(text, openPos) {
|
|
15659
|
+
let depth = 0;
|
|
15660
|
+
for (let i = openPos; i < text.length; i++) {
|
|
15661
|
+
if (text[i] === "(") {
|
|
15662
|
+
depth++;
|
|
15663
|
+
} else if (text[i] === ")") {
|
|
15664
|
+
depth--;
|
|
15665
|
+
if (depth === 0) {
|
|
15666
|
+
return i;
|
|
15667
|
+
}
|
|
15668
|
+
}
|
|
15669
|
+
}
|
|
15670
|
+
return -1;
|
|
15671
|
+
}
|
|
15672
|
+
function unwrapExport(content) {
|
|
15673
|
+
const pattern = /export\s+default\s+withGlasstraceConfig\s*\(/;
|
|
15674
|
+
const match = pattern.exec(content);
|
|
15675
|
+
if (!match) {
|
|
15676
|
+
return { content, unwrapped: false };
|
|
15677
|
+
}
|
|
15678
|
+
const openParenIdx = match.index + match[0].length - 1;
|
|
15679
|
+
const closeParenIdx = findMatchingParen(content, openParenIdx);
|
|
15680
|
+
if (closeParenIdx === -1) {
|
|
15681
|
+
return { content, unwrapped: false };
|
|
15682
|
+
}
|
|
15683
|
+
const innerExpr = content.slice(openParenIdx + 1, closeParenIdx).trim();
|
|
15684
|
+
if (innerExpr.length === 0) {
|
|
15685
|
+
return { content, unwrapped: false };
|
|
15686
|
+
}
|
|
15687
|
+
const before = content.slice(0, match.index);
|
|
15688
|
+
const afterClose = content.slice(closeParenIdx + 1);
|
|
15689
|
+
const trailing = afterClose.replace(/^;?\s*/, "");
|
|
15690
|
+
const result = before + `export default ${innerExpr};
|
|
15691
|
+
` + trailing;
|
|
15692
|
+
return { content: result, unwrapped: true };
|
|
15693
|
+
}
|
|
15694
|
+
function unwrapCJSExport(content) {
|
|
15695
|
+
const pattern = /module\.exports\s*=\s*withGlasstraceConfig\s*\(/;
|
|
15696
|
+
const match = pattern.exec(content);
|
|
15697
|
+
if (!match) {
|
|
15698
|
+
return { content, unwrapped: false };
|
|
15699
|
+
}
|
|
15700
|
+
const openParenIdx = match.index + match[0].length - 1;
|
|
15701
|
+
const closeParenIdx = findMatchingParen(content, openParenIdx);
|
|
15702
|
+
if (closeParenIdx === -1) {
|
|
15703
|
+
return { content, unwrapped: false };
|
|
15704
|
+
}
|
|
15705
|
+
const innerExpr = content.slice(openParenIdx + 1, closeParenIdx).trim();
|
|
15706
|
+
if (innerExpr.length === 0) {
|
|
15707
|
+
return { content, unwrapped: false };
|
|
15708
|
+
}
|
|
15709
|
+
const before = content.slice(0, match.index);
|
|
15710
|
+
const afterClose = content.slice(closeParenIdx + 1);
|
|
15711
|
+
const trailing = afterClose.replace(/^;?\s*/, "");
|
|
15712
|
+
const result = before + `module.exports = ${innerExpr};
|
|
15713
|
+
` + trailing;
|
|
15714
|
+
return { content: result, unwrapped: true };
|
|
15715
|
+
}
|
|
15716
|
+
function removeGlasstraceConfigImport(content) {
|
|
15717
|
+
const esmSoleImport = /import\s*\{\s*withGlasstraceConfig\s*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/;
|
|
15718
|
+
if (esmSoleImport.test(content)) {
|
|
15719
|
+
return content.replace(esmSoleImport, "");
|
|
15720
|
+
}
|
|
15721
|
+
const esmMultiImport = /import\s*\{([^}]*)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
15722
|
+
const multiMatch = esmMultiImport.exec(content);
|
|
15723
|
+
if (multiMatch) {
|
|
15724
|
+
const specifiers = multiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "withGlasstraceConfig");
|
|
15725
|
+
if (specifiers.length === 0) {
|
|
15726
|
+
return content.replace(
|
|
15727
|
+
/import\s*\{[^}]*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/,
|
|
15728
|
+
""
|
|
15729
|
+
);
|
|
15730
|
+
}
|
|
15731
|
+
const newImport = `import { ${specifiers.join(", ")} } from "@glasstrace/sdk"`;
|
|
15732
|
+
return content.replace(multiMatch[0], newImport);
|
|
15733
|
+
}
|
|
15734
|
+
const cjsSoleRequire = /const\s*\{\s*withGlasstraceConfig\s*\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)\s*;?\s*\n?/;
|
|
15735
|
+
if (cjsSoleRequire.test(content)) {
|
|
15736
|
+
return content.replace(cjsSoleRequire, "");
|
|
15737
|
+
}
|
|
15738
|
+
const cjsMultiRequire = /const\s*\{([^}]*)\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)/;
|
|
15739
|
+
const cjsMultiMatch = cjsMultiRequire.exec(content);
|
|
15740
|
+
if (cjsMultiMatch) {
|
|
15741
|
+
const specifiers = cjsMultiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "withGlasstraceConfig");
|
|
15742
|
+
if (specifiers.length === 0) {
|
|
15743
|
+
return content.replace(
|
|
15744
|
+
/const\s*\{[^}]*\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)\s*;?\s*\n?/,
|
|
15745
|
+
""
|
|
15746
|
+
);
|
|
15747
|
+
}
|
|
15748
|
+
const newRequire = `const { ${specifiers.join(", ")} } = require("@glasstrace/sdk")`;
|
|
15749
|
+
return content.replace(cjsMultiMatch[0], newRequire);
|
|
15750
|
+
}
|
|
15751
|
+
return content;
|
|
15752
|
+
}
|
|
15753
|
+
function cleanLeadingBlankLines(content) {
|
|
15754
|
+
return content.replace(/^\n{2,}/, "\n");
|
|
15755
|
+
}
|
|
15756
|
+
function isInitCreatedInstrumentation(content) {
|
|
15757
|
+
const lines = content.split("\n");
|
|
15758
|
+
const importLines = lines.filter(
|
|
15759
|
+
(l) => /^\s*import\s/.test(l) && !l.trim().startsWith("//")
|
|
15760
|
+
);
|
|
15761
|
+
const nonGlasstraceImports = importLines.filter(
|
|
15762
|
+
(l) => !l.includes("@glasstrace/sdk")
|
|
15763
|
+
);
|
|
15764
|
+
if (nonGlasstraceImports.length > 0) {
|
|
15765
|
+
return false;
|
|
15766
|
+
}
|
|
15767
|
+
const registerFnRegex = /export\s+(?:async\s+)?function\s+register\s*\([^)]*\)\s*\{/;
|
|
15768
|
+
const match = registerFnRegex.exec(content);
|
|
15769
|
+
if (!match) {
|
|
15770
|
+
return false;
|
|
15771
|
+
}
|
|
15772
|
+
const afterBrace = content.slice(match.index + match[0].length);
|
|
15773
|
+
const closingBraceIdx = findMatchingBrace(content, match.index + match[0].length - 1);
|
|
15774
|
+
if (closingBraceIdx === -1) {
|
|
15775
|
+
return false;
|
|
15776
|
+
}
|
|
15777
|
+
const body = afterBrace.slice(0, closingBraceIdx - (match.index + match[0].length));
|
|
15778
|
+
const bodyLines = body.split("\n");
|
|
15779
|
+
const statements = bodyLines.filter((l) => {
|
|
15780
|
+
const trimmed = l.trim();
|
|
15781
|
+
return trimmed !== "" && !trimmed.startsWith("//");
|
|
15782
|
+
});
|
|
15783
|
+
if (statements.length !== 1) {
|
|
15784
|
+
return false;
|
|
15785
|
+
}
|
|
15786
|
+
if (!/^\s*registerGlasstrace\s*\(\s*\)\s*;?\s*$/.test(statements[0])) {
|
|
15787
|
+
return false;
|
|
15788
|
+
}
|
|
15789
|
+
const beforeFn = content.slice(0, match.index);
|
|
15790
|
+
const afterFn = content.slice(closingBraceIdx + 1);
|
|
15791
|
+
const topLevelBefore = beforeFn.split("\n").filter((l) => {
|
|
15792
|
+
const trimmed = l.trim();
|
|
15793
|
+
return trimmed !== "" && !trimmed.startsWith("//") && !trimmed.startsWith("import ") && !trimmed.startsWith("import{");
|
|
15794
|
+
});
|
|
15795
|
+
const topLevelAfter = afterFn.split("\n").filter((l) => {
|
|
15796
|
+
const trimmed = l.trim();
|
|
15797
|
+
return trimmed !== "" && !trimmed.startsWith("//");
|
|
15798
|
+
});
|
|
15799
|
+
return topLevelBefore.length === 0 && topLevelAfter.length === 0;
|
|
15800
|
+
}
|
|
15801
|
+
function findMatchingBrace(text, openPos) {
|
|
15802
|
+
let depth = 0;
|
|
15803
|
+
for (let i = openPos; i < text.length; i++) {
|
|
15804
|
+
if (text[i] === "{") {
|
|
15805
|
+
depth++;
|
|
15806
|
+
} else if (text[i] === "}") {
|
|
15807
|
+
depth--;
|
|
15808
|
+
if (depth === 0) {
|
|
15809
|
+
return i;
|
|
15810
|
+
}
|
|
15811
|
+
}
|
|
15812
|
+
}
|
|
15813
|
+
return -1;
|
|
15814
|
+
}
|
|
15815
|
+
function removeRegisterGlasstrace(content) {
|
|
15816
|
+
let result = content;
|
|
15817
|
+
result = result.replace(
|
|
15818
|
+
/[ \t]*\/\/\s*Glasstrace must be registered[^\n]*\n(?:[ \t]*\/\/[^\n]*\n)*[ \t]*registerGlasstrace\s*\(\s*\)\s*;?\s*\n?/g,
|
|
15819
|
+
""
|
|
15820
|
+
);
|
|
15821
|
+
result = result.replace(
|
|
15822
|
+
/[ \t]*registerGlasstrace\s*\(\s*\)\s*;?\s*\n?/g,
|
|
15823
|
+
""
|
|
15824
|
+
);
|
|
15825
|
+
const soleImportPattern = /import\s*\{\s*registerGlasstrace\s*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/;
|
|
15826
|
+
if (soleImportPattern.test(result)) {
|
|
15827
|
+
result = result.replace(soleImportPattern, "");
|
|
15828
|
+
} else {
|
|
15829
|
+
const multiImportPattern = /import\s*\{([^}]*)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
15830
|
+
const multiMatch = multiImportPattern.exec(result);
|
|
15831
|
+
if (multiMatch) {
|
|
15832
|
+
const specifiers = multiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "registerGlasstrace");
|
|
15833
|
+
if (specifiers.length === 0) {
|
|
15834
|
+
result = result.replace(
|
|
15835
|
+
/import\s*\{[^}]*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/,
|
|
15836
|
+
""
|
|
15837
|
+
);
|
|
15838
|
+
} else {
|
|
15839
|
+
const newImport = `import { ${specifiers.join(", ")} } from "@glasstrace/sdk"`;
|
|
15840
|
+
result = result.replace(multiMatch[0], newImport);
|
|
15841
|
+
}
|
|
15842
|
+
}
|
|
15843
|
+
}
|
|
15844
|
+
return cleanLeadingBlankLines(result);
|
|
15845
|
+
}
|
|
15846
|
+
function removeMarkerSection(content) {
|
|
15847
|
+
const lines = content.split("\n");
|
|
15848
|
+
let startIdx = -1;
|
|
15849
|
+
let endIdx = -1;
|
|
15850
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15851
|
+
const trimmed = lines[i].trim();
|
|
15852
|
+
if (trimmed === "<!-- glasstrace:mcp:start -->" || trimmed === "# glasstrace:mcp:start") {
|
|
15853
|
+
startIdx = i;
|
|
15854
|
+
} else if ((trimmed === "<!-- glasstrace:mcp:end -->" || trimmed === "# glasstrace:mcp:end") && startIdx !== -1) {
|
|
15855
|
+
endIdx = i;
|
|
15856
|
+
break;
|
|
15857
|
+
}
|
|
15858
|
+
}
|
|
15859
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
15860
|
+
return { content, removed: false };
|
|
15861
|
+
}
|
|
15862
|
+
const before = lines.slice(0, startIdx);
|
|
15863
|
+
const after = lines.slice(endIdx + 1);
|
|
15864
|
+
while (before.length > 0 && before[before.length - 1].trim() === "") {
|
|
15865
|
+
before.pop();
|
|
15866
|
+
}
|
|
15867
|
+
const result = [...before, ...after].join("\n");
|
|
15868
|
+
const trimmedResult = result.trimEnd();
|
|
15869
|
+
return {
|
|
15870
|
+
content: trimmedResult.length > 0 ? trimmedResult + "\n" : "",
|
|
15871
|
+
removed: true
|
|
15872
|
+
};
|
|
15873
|
+
}
|
|
15874
|
+
function processJsonMcpConfig(content) {
|
|
15875
|
+
let parsed;
|
|
15876
|
+
try {
|
|
15877
|
+
parsed = JSON.parse(content);
|
|
15878
|
+
} catch {
|
|
15879
|
+
return { action: "skipped" };
|
|
15880
|
+
}
|
|
15881
|
+
const mcpServers = parsed["mcpServers"];
|
|
15882
|
+
if (!mcpServers || typeof mcpServers !== "object" || !("glasstrace" in mcpServers)) {
|
|
15883
|
+
return { action: "skipped" };
|
|
15884
|
+
}
|
|
15885
|
+
const remainingServers = Object.keys(mcpServers).filter((k) => k !== "glasstrace");
|
|
15886
|
+
const otherTopLevelKeys = Object.keys(parsed).filter((k) => k !== "mcpServers");
|
|
15887
|
+
if (remainingServers.length === 0 && otherTopLevelKeys.length === 0) {
|
|
15888
|
+
return { action: "deleted" };
|
|
15889
|
+
}
|
|
15890
|
+
const { glasstrace: _, ...rest } = mcpServers;
|
|
15891
|
+
void _;
|
|
15892
|
+
if (remainingServers.length > 0) {
|
|
15893
|
+
parsed["mcpServers"] = rest;
|
|
15894
|
+
} else {
|
|
15895
|
+
delete parsed["mcpServers"];
|
|
15896
|
+
}
|
|
15897
|
+
return { action: "removed-key", content: JSON.stringify(parsed, null, 2) + "\n" };
|
|
15898
|
+
}
|
|
15899
|
+
function processTomlMcpConfig(content) {
|
|
15900
|
+
if (!content.includes("[mcp_servers.glasstrace]")) {
|
|
15901
|
+
return { action: "skipped" };
|
|
15902
|
+
}
|
|
15903
|
+
const lines = content.split("\n");
|
|
15904
|
+
const startIdx = lines.findIndex(
|
|
15905
|
+
(l) => l.trim() === "[mcp_servers.glasstrace]"
|
|
15906
|
+
);
|
|
15907
|
+
if (startIdx === -1) {
|
|
15908
|
+
return { action: "skipped" };
|
|
15909
|
+
}
|
|
15910
|
+
let endIdx = lines.length;
|
|
15911
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
15912
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
15913
|
+
endIdx = i;
|
|
15914
|
+
break;
|
|
15915
|
+
}
|
|
15916
|
+
}
|
|
15917
|
+
const before = lines.slice(0, startIdx);
|
|
15918
|
+
const after = lines.slice(endIdx);
|
|
15919
|
+
while (before.length > 0 && before[before.length - 1].trim() === "") {
|
|
15920
|
+
before.pop();
|
|
15921
|
+
}
|
|
15922
|
+
const result = [...before, ...after].join("\n").trimEnd();
|
|
15923
|
+
if (result.trim().length === 0) {
|
|
15924
|
+
return { action: "deleted" };
|
|
15925
|
+
}
|
|
15926
|
+
return { action: "removed-section", content: result + "\n" };
|
|
15927
|
+
}
|
|
15928
|
+
async function runUninit(options) {
|
|
15929
|
+
const { projectRoot, dryRun } = options;
|
|
15930
|
+
const summary = [];
|
|
15931
|
+
const warnings = [];
|
|
15932
|
+
const errors = [];
|
|
15933
|
+
const prefix = dryRun ? "[dry run] " : "";
|
|
15934
|
+
try {
|
|
15935
|
+
let configHandled = false;
|
|
15936
|
+
for (const name of NEXT_CONFIG_NAMES3) {
|
|
15937
|
+
const configPath = path5.join(projectRoot, name);
|
|
15938
|
+
if (!fs5.existsSync(configPath)) {
|
|
15939
|
+
continue;
|
|
15940
|
+
}
|
|
15941
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
15942
|
+
if (!content.includes("withGlasstraceConfig")) {
|
|
15943
|
+
continue;
|
|
15944
|
+
}
|
|
15945
|
+
const isESM = name.endsWith(".ts") || name.endsWith(".mjs");
|
|
15946
|
+
const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
|
|
15947
|
+
if (unwrapResult.unwrapped) {
|
|
15948
|
+
const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
|
|
15949
|
+
const final = cleanLeadingBlankLines(cleaned);
|
|
15950
|
+
if (!dryRun) {
|
|
15951
|
+
fs5.writeFileSync(configPath, final, "utf-8");
|
|
15952
|
+
}
|
|
15953
|
+
summary.push(`${prefix}Unwrapped withGlasstraceConfig from ${name}`);
|
|
15954
|
+
configHandled = true;
|
|
15955
|
+
break;
|
|
15956
|
+
} else {
|
|
15957
|
+
warnings.push(
|
|
15958
|
+
`${name} contains withGlasstraceConfig but could not be automatically unwrapped. Please remove withGlasstraceConfig() manually.`
|
|
15959
|
+
);
|
|
15960
|
+
configHandled = true;
|
|
15961
|
+
break;
|
|
15962
|
+
}
|
|
15963
|
+
}
|
|
15964
|
+
if (!configHandled) {
|
|
15965
|
+
}
|
|
15966
|
+
} catch (err) {
|
|
15967
|
+
errors.push(
|
|
15968
|
+
`Failed to process next.config: ${err instanceof Error ? err.message : String(err)}`
|
|
15969
|
+
);
|
|
15970
|
+
}
|
|
15971
|
+
try {
|
|
15972
|
+
const instrPath = path5.join(projectRoot, "instrumentation.ts");
|
|
15973
|
+
if (fs5.existsSync(instrPath)) {
|
|
15974
|
+
const content = fs5.readFileSync(instrPath, "utf-8");
|
|
15975
|
+
if (content.includes("registerGlasstrace") || content.includes("@glasstrace/sdk")) {
|
|
15976
|
+
if (isInitCreatedInstrumentation(content)) {
|
|
15977
|
+
if (!dryRun) {
|
|
15978
|
+
fs5.unlinkSync(instrPath);
|
|
15979
|
+
}
|
|
15980
|
+
summary.push(`${prefix}Deleted instrumentation.ts (init-created)`);
|
|
15981
|
+
} else {
|
|
15982
|
+
const cleaned = removeRegisterGlasstrace(content);
|
|
15983
|
+
if (cleaned !== content) {
|
|
15984
|
+
if (!dryRun) {
|
|
15985
|
+
fs5.writeFileSync(instrPath, cleaned, "utf-8");
|
|
15986
|
+
}
|
|
15987
|
+
summary.push(
|
|
15988
|
+
`${prefix}Removed registerGlasstrace() from instrumentation.ts`
|
|
15989
|
+
);
|
|
15990
|
+
}
|
|
15991
|
+
}
|
|
15992
|
+
}
|
|
15993
|
+
}
|
|
15994
|
+
} catch (err) {
|
|
15995
|
+
errors.push(
|
|
15996
|
+
`Failed to process instrumentation.ts: ${err instanceof Error ? err.message : String(err)}`
|
|
15997
|
+
);
|
|
15998
|
+
}
|
|
15999
|
+
try {
|
|
16000
|
+
const glasstraceDir = path5.join(projectRoot, ".glasstrace");
|
|
16001
|
+
if (fs5.existsSync(glasstraceDir)) {
|
|
16002
|
+
if (!dryRun) {
|
|
16003
|
+
fs5.rmSync(glasstraceDir, { recursive: true, force: true });
|
|
16004
|
+
}
|
|
16005
|
+
summary.push(`${prefix}Removed .glasstrace/ directory`);
|
|
16006
|
+
}
|
|
16007
|
+
} catch (err) {
|
|
16008
|
+
errors.push(
|
|
16009
|
+
`Failed to remove .glasstrace/: ${err instanceof Error ? err.message : String(err)}`
|
|
16010
|
+
);
|
|
16011
|
+
}
|
|
16012
|
+
try {
|
|
16013
|
+
const envPath = path5.join(projectRoot, ".env.local");
|
|
16014
|
+
if (fs5.existsSync(envPath)) {
|
|
16015
|
+
const content = fs5.readFileSync(envPath, "utf-8");
|
|
16016
|
+
const lines = content.split("\n");
|
|
16017
|
+
const filtered = lines.filter((line) => {
|
|
16018
|
+
const trimmed = line.trim();
|
|
16019
|
+
return !(/^\s*#?\s*GLASSTRACE_API_KEY\s*=/.test(trimmed) || /^\s*#?\s*GLASSTRACE_COVERAGE_MAP\s*=/.test(trimmed));
|
|
16020
|
+
});
|
|
16021
|
+
if (filtered.length !== lines.length) {
|
|
16022
|
+
const result = filtered.join("\n");
|
|
16023
|
+
if (result.trim().length === 0) {
|
|
16024
|
+
if (!dryRun) {
|
|
16025
|
+
fs5.unlinkSync(envPath);
|
|
16026
|
+
}
|
|
16027
|
+
summary.push(`${prefix}Deleted .env.local (no remaining entries)`);
|
|
16028
|
+
} else {
|
|
16029
|
+
if (!dryRun) {
|
|
16030
|
+
fs5.writeFileSync(envPath, result, "utf-8");
|
|
16031
|
+
}
|
|
16032
|
+
summary.push(`${prefix}Removed GLASSTRACE entries from .env.local`);
|
|
16033
|
+
}
|
|
16034
|
+
}
|
|
16035
|
+
}
|
|
16036
|
+
} catch (err) {
|
|
16037
|
+
errors.push(
|
|
16038
|
+
`Failed to process .env.local: ${err instanceof Error ? err.message : String(err)}`
|
|
16039
|
+
);
|
|
16040
|
+
}
|
|
16041
|
+
try {
|
|
16042
|
+
const gitignorePath = path5.join(projectRoot, ".gitignore");
|
|
16043
|
+
if (fs5.existsSync(gitignorePath)) {
|
|
16044
|
+
const content = fs5.readFileSync(gitignorePath, "utf-8");
|
|
16045
|
+
const lines = content.split("\n");
|
|
16046
|
+
const mcpGitignoreEntries = /* @__PURE__ */ new Set([
|
|
16047
|
+
".glasstrace/",
|
|
16048
|
+
".mcp.json",
|
|
16049
|
+
".cursor/mcp.json",
|
|
16050
|
+
".gemini/settings.json",
|
|
16051
|
+
".codex/config.toml"
|
|
16052
|
+
]);
|
|
16053
|
+
const filtered = lines.filter(
|
|
16054
|
+
(line) => !mcpGitignoreEntries.has(line.trim())
|
|
16055
|
+
);
|
|
16056
|
+
if (filtered.length !== lines.length) {
|
|
16057
|
+
const result = filtered.join("\n");
|
|
16058
|
+
if (result.trim().length === 0) {
|
|
16059
|
+
if (!dryRun) {
|
|
16060
|
+
fs5.unlinkSync(gitignorePath);
|
|
16061
|
+
}
|
|
16062
|
+
summary.push(`${prefix}Deleted .gitignore (no remaining entries)`);
|
|
16063
|
+
} else {
|
|
16064
|
+
if (!dryRun) {
|
|
16065
|
+
fs5.writeFileSync(gitignorePath, result, "utf-8");
|
|
16066
|
+
}
|
|
16067
|
+
summary.push(`${prefix}Removed Glasstrace entries from .gitignore`);
|
|
16068
|
+
}
|
|
16069
|
+
}
|
|
16070
|
+
}
|
|
16071
|
+
} catch (err) {
|
|
16072
|
+
errors.push(
|
|
16073
|
+
`Failed to process .gitignore: ${err instanceof Error ? err.message : String(err)}`
|
|
16074
|
+
);
|
|
16075
|
+
}
|
|
16076
|
+
try {
|
|
16077
|
+
for (const configFile of MCP_CONFIG_FILES) {
|
|
16078
|
+
const configPath = path5.join(projectRoot, configFile);
|
|
16079
|
+
if (!fs5.existsSync(configPath)) {
|
|
16080
|
+
continue;
|
|
16081
|
+
}
|
|
16082
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
16083
|
+
const result = processJsonMcpConfig(content);
|
|
16084
|
+
if (result.action === "deleted") {
|
|
16085
|
+
if (!dryRun) {
|
|
16086
|
+
fs5.unlinkSync(configPath);
|
|
16087
|
+
}
|
|
16088
|
+
summary.push(`${prefix}Deleted ${configFile}`);
|
|
16089
|
+
} else if (result.action === "removed-key" && result.content !== void 0) {
|
|
16090
|
+
if (!dryRun) {
|
|
16091
|
+
fs5.writeFileSync(configPath, result.content, "utf-8");
|
|
16092
|
+
}
|
|
16093
|
+
summary.push(`${prefix}Removed glasstrace from ${configFile}`);
|
|
16094
|
+
}
|
|
16095
|
+
}
|
|
16096
|
+
const codexConfigPath = path5.join(projectRoot, ".codex", "config.toml");
|
|
16097
|
+
if (fs5.existsSync(codexConfigPath)) {
|
|
16098
|
+
const content = fs5.readFileSync(codexConfigPath, "utf-8");
|
|
16099
|
+
const tomlResult = processTomlMcpConfig(content);
|
|
16100
|
+
if (tomlResult.action === "deleted") {
|
|
16101
|
+
if (!dryRun) {
|
|
16102
|
+
fs5.unlinkSync(codexConfigPath);
|
|
16103
|
+
}
|
|
16104
|
+
summary.push(`${prefix}Deleted .codex/config.toml`);
|
|
16105
|
+
} else if (tomlResult.action === "removed-section" && tomlResult.content !== void 0) {
|
|
16106
|
+
if (!dryRun) {
|
|
16107
|
+
fs5.writeFileSync(codexConfigPath, tomlResult.content, "utf-8");
|
|
16108
|
+
}
|
|
16109
|
+
summary.push(`${prefix}Removed glasstrace from .codex/config.toml`);
|
|
16110
|
+
}
|
|
16111
|
+
}
|
|
16112
|
+
const hasWindsurfMarkers = fs5.existsSync(path5.join(projectRoot, ".windsurfrules")) || fs5.existsSync(path5.join(projectRoot, ".windsurf"));
|
|
16113
|
+
if (hasWindsurfMarkers) {
|
|
16114
|
+
const windsurfConfigPath = path5.join(
|
|
16115
|
+
os.homedir(),
|
|
16116
|
+
".codeium",
|
|
16117
|
+
"windsurf",
|
|
16118
|
+
"mcp_config.json"
|
|
16119
|
+
);
|
|
16120
|
+
if (fs5.existsSync(windsurfConfigPath)) {
|
|
16121
|
+
const content = fs5.readFileSync(windsurfConfigPath, "utf-8");
|
|
16122
|
+
const windsurfResult = processJsonMcpConfig(content);
|
|
16123
|
+
if (windsurfResult.action === "deleted") {
|
|
16124
|
+
if (!dryRun) {
|
|
16125
|
+
fs5.unlinkSync(windsurfConfigPath);
|
|
16126
|
+
}
|
|
16127
|
+
summary.push(`${prefix}Deleted Windsurf MCP config`);
|
|
16128
|
+
} else if (windsurfResult.action === "removed-key" && windsurfResult.content !== void 0) {
|
|
16129
|
+
if (!dryRun) {
|
|
16130
|
+
fs5.writeFileSync(windsurfConfigPath, windsurfResult.content, "utf-8");
|
|
16131
|
+
}
|
|
16132
|
+
summary.push(`${prefix}Removed glasstrace from Windsurf MCP config`);
|
|
16133
|
+
}
|
|
16134
|
+
}
|
|
16135
|
+
}
|
|
16136
|
+
} catch (err) {
|
|
16137
|
+
errors.push(
|
|
16138
|
+
`Failed to process MCP config: ${err instanceof Error ? err.message : String(err)}`
|
|
16139
|
+
);
|
|
16140
|
+
}
|
|
16141
|
+
try {
|
|
16142
|
+
for (const infoFile of AGENT_INFO_FILES) {
|
|
16143
|
+
const filePath = path5.join(projectRoot, infoFile);
|
|
16144
|
+
if (!fs5.existsSync(filePath)) {
|
|
16145
|
+
continue;
|
|
16146
|
+
}
|
|
16147
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
16148
|
+
const result = removeMarkerSection(content);
|
|
16149
|
+
if (result.removed) {
|
|
16150
|
+
if (result.content.trim().length === 0) {
|
|
16151
|
+
if (!dryRun) {
|
|
16152
|
+
fs5.unlinkSync(filePath);
|
|
16153
|
+
}
|
|
16154
|
+
summary.push(`${prefix}Deleted ${infoFile} (only contained Glasstrace section)`);
|
|
16155
|
+
} else {
|
|
16156
|
+
if (!dryRun) {
|
|
16157
|
+
fs5.writeFileSync(filePath, result.content, "utf-8");
|
|
16158
|
+
}
|
|
16159
|
+
summary.push(`${prefix}Removed Glasstrace section from ${infoFile}`);
|
|
16160
|
+
}
|
|
16161
|
+
}
|
|
16162
|
+
}
|
|
16163
|
+
} catch (err) {
|
|
16164
|
+
errors.push(
|
|
16165
|
+
`Failed to process agent info files: ${err instanceof Error ? err.message : String(err)}`
|
|
16166
|
+
);
|
|
16167
|
+
}
|
|
16168
|
+
if (summary.length === 0 && errors.length === 0) {
|
|
16169
|
+
summary.push("No Glasstrace artifacts found \u2014 nothing to do.");
|
|
16170
|
+
}
|
|
16171
|
+
return { exitCode: errors.length > 0 ? 1 : 0, summary, warnings, errors };
|
|
16172
|
+
}
|
|
16173
|
+
var fs5, os, path5, NEXT_CONFIG_NAMES3, MCP_CONFIG_FILES, AGENT_INFO_FILES;
|
|
16174
|
+
var init_uninit = __esm({
|
|
16175
|
+
"src/cli/uninit.ts"() {
|
|
16176
|
+
"use strict";
|
|
16177
|
+
fs5 = __toESM(require("fs"), 1);
|
|
16178
|
+
os = __toESM(require("os"), 1);
|
|
16179
|
+
path5 = __toESM(require("path"), 1);
|
|
16180
|
+
NEXT_CONFIG_NAMES3 = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
16181
|
+
MCP_CONFIG_FILES = [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json"];
|
|
16182
|
+
AGENT_INFO_FILES = [
|
|
16183
|
+
"CLAUDE.md",
|
|
16184
|
+
"codex.md",
|
|
16185
|
+
".cursorrules"
|
|
16186
|
+
];
|
|
16187
|
+
}
|
|
16188
|
+
});
|
|
16189
|
+
|
|
15577
16190
|
// src/cli/init.ts
|
|
15578
16191
|
var init_exports = {};
|
|
15579
16192
|
__export(init_exports, {
|
|
@@ -15581,8 +16194,8 @@ __export(init_exports, {
|
|
|
15581
16194
|
runInit: () => runInit
|
|
15582
16195
|
});
|
|
15583
16196
|
module.exports = __toCommonJS(init_exports);
|
|
15584
|
-
var
|
|
15585
|
-
var
|
|
16197
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
16198
|
+
var path6 = __toESM(require("path"), 1);
|
|
15586
16199
|
var readline = __toESM(require("readline"), 1);
|
|
15587
16200
|
init_scaffolder();
|
|
15588
16201
|
|
|
@@ -15761,6 +16374,240 @@ init_detect();
|
|
|
15761
16374
|
init_configs();
|
|
15762
16375
|
init_inject();
|
|
15763
16376
|
init_constants();
|
|
16377
|
+
|
|
16378
|
+
// src/cli/monorepo.ts
|
|
16379
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
16380
|
+
var path3 = __toESM(require("path"), 1);
|
|
16381
|
+
var NEXT_CONFIG_NAMES2 = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
16382
|
+
function resolveProjectRoot(cwd) {
|
|
16383
|
+
if (hasNextConfig(cwd)) {
|
|
16384
|
+
return { projectRoot: cwd, isMonorepo: false };
|
|
16385
|
+
}
|
|
16386
|
+
if (hasNextDependency(cwd)) {
|
|
16387
|
+
return { projectRoot: cwd, isMonorepo: false };
|
|
16388
|
+
}
|
|
16389
|
+
if (isMonorepoRoot(cwd)) {
|
|
16390
|
+
const apps = findNextJsApps(cwd);
|
|
16391
|
+
if (apps.length === 0) {
|
|
16392
|
+
throw new Error(
|
|
16393
|
+
"This is a monorepo but no Next.js apps were found in workspace packages."
|
|
16394
|
+
);
|
|
16395
|
+
}
|
|
16396
|
+
if (apps.length === 1) {
|
|
16397
|
+
const appDir = apps[0];
|
|
16398
|
+
const relativePath = path3.relative(cwd, appDir);
|
|
16399
|
+
return {
|
|
16400
|
+
projectRoot: appDir,
|
|
16401
|
+
isMonorepo: true,
|
|
16402
|
+
appRelativePath: relativePath
|
|
16403
|
+
};
|
|
16404
|
+
}
|
|
16405
|
+
const appList = apps.map((app) => ` - ${path3.relative(cwd, app)}`).join("\n");
|
|
16406
|
+
throw new Error(
|
|
16407
|
+
`Found multiple Next.js apps:
|
|
16408
|
+
${appList}
|
|
16409
|
+
Run init from the specific app directory you want to instrument.`
|
|
16410
|
+
);
|
|
16411
|
+
}
|
|
16412
|
+
throw new Error(
|
|
16413
|
+
"No Next.js project found in the current directory.\nRun this command from your Next.js app directory, or from a monorepo root."
|
|
16414
|
+
);
|
|
16415
|
+
}
|
|
16416
|
+
function hasNextConfig(dir) {
|
|
16417
|
+
return NEXT_CONFIG_NAMES2.some(
|
|
16418
|
+
(name) => fs3.existsSync(path3.join(dir, name))
|
|
16419
|
+
);
|
|
16420
|
+
}
|
|
16421
|
+
function hasNextDependency(dir) {
|
|
16422
|
+
const packageJsonPath = path3.join(dir, "package.json");
|
|
16423
|
+
if (!fs3.existsSync(packageJsonPath)) return false;
|
|
16424
|
+
try {
|
|
16425
|
+
const content = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
16426
|
+
const pkg = JSON.parse(content);
|
|
16427
|
+
const deps = pkg["dependencies"];
|
|
16428
|
+
const devDeps = pkg["devDependencies"];
|
|
16429
|
+
if (typeof deps === "object" && deps !== null && "next" in deps) return true;
|
|
16430
|
+
if (typeof devDeps === "object" && devDeps !== null && "next" in devDeps) return true;
|
|
16431
|
+
} catch {
|
|
16432
|
+
}
|
|
16433
|
+
return false;
|
|
16434
|
+
}
|
|
16435
|
+
function isMonorepoRoot(dir) {
|
|
16436
|
+
if (fs3.existsSync(path3.join(dir, "pnpm-workspace.yaml"))) return true;
|
|
16437
|
+
if (fs3.existsSync(path3.join(dir, "turbo.json"))) return true;
|
|
16438
|
+
if (fs3.existsSync(path3.join(dir, "lerna.json"))) return true;
|
|
16439
|
+
const packageJsonPath = path3.join(dir, "package.json");
|
|
16440
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
16441
|
+
try {
|
|
16442
|
+
const content = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
16443
|
+
const pkg = JSON.parse(content);
|
|
16444
|
+
if (pkg["workspaces"] !== void 0) return true;
|
|
16445
|
+
} catch {
|
|
16446
|
+
}
|
|
16447
|
+
}
|
|
16448
|
+
return false;
|
|
16449
|
+
}
|
|
16450
|
+
function findNextJsApps(monorepoRoot) {
|
|
16451
|
+
const { includeGlobs, negationPatterns } = collectWorkspaceGlobs(monorepoRoot);
|
|
16452
|
+
if (includeGlobs.length === 0) {
|
|
16453
|
+
throw new Error(
|
|
16454
|
+
'Monorepo detected but no workspace configuration found.\nAdd a "workspaces" field to package.json or create pnpm-workspace.yaml.'
|
|
16455
|
+
);
|
|
16456
|
+
}
|
|
16457
|
+
const workspaceDirs = expandGlobs(monorepoRoot, includeGlobs);
|
|
16458
|
+
const excludedDirs = expandGlobs(monorepoRoot, negationPatterns);
|
|
16459
|
+
const excludedSet = new Set(excludedDirs);
|
|
16460
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16461
|
+
const nextApps = [];
|
|
16462
|
+
for (const dir of workspaceDirs) {
|
|
16463
|
+
if (seen.has(dir)) continue;
|
|
16464
|
+
seen.add(dir);
|
|
16465
|
+
if (excludedSet.has(dir)) continue;
|
|
16466
|
+
if (hasNextConfig(dir) || hasNextDependency(dir)) {
|
|
16467
|
+
nextApps.push(dir);
|
|
16468
|
+
}
|
|
16469
|
+
}
|
|
16470
|
+
return nextApps.sort();
|
|
16471
|
+
}
|
|
16472
|
+
function collectWorkspaceGlobs(root) {
|
|
16473
|
+
const globs = [];
|
|
16474
|
+
const negations = [];
|
|
16475
|
+
const pnpmPath = path3.join(root, "pnpm-workspace.yaml");
|
|
16476
|
+
if (fs3.existsSync(pnpmPath)) {
|
|
16477
|
+
const content = fs3.readFileSync(pnpmPath, "utf-8");
|
|
16478
|
+
const parsed = parsePnpmWorkspaceYaml(content);
|
|
16479
|
+
globs.push(...parsed.includeGlobs);
|
|
16480
|
+
negations.push(...parsed.negationPatterns);
|
|
16481
|
+
}
|
|
16482
|
+
const packageJsonPath = path3.join(root, "package.json");
|
|
16483
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
16484
|
+
try {
|
|
16485
|
+
const content = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
16486
|
+
const pkg = JSON.parse(content);
|
|
16487
|
+
globs.push(...parsePackageJsonWorkspaces(pkg));
|
|
16488
|
+
} catch {
|
|
16489
|
+
}
|
|
16490
|
+
}
|
|
16491
|
+
const lernaPath = path3.join(root, "lerna.json");
|
|
16492
|
+
if (fs3.existsSync(lernaPath)) {
|
|
16493
|
+
try {
|
|
16494
|
+
const content = fs3.readFileSync(lernaPath, "utf-8");
|
|
16495
|
+
const lerna = JSON.parse(content);
|
|
16496
|
+
const packages = lerna["packages"];
|
|
16497
|
+
if (Array.isArray(packages)) {
|
|
16498
|
+
for (const pkg of packages) {
|
|
16499
|
+
if (typeof pkg === "string") {
|
|
16500
|
+
globs.push(pkg);
|
|
16501
|
+
}
|
|
16502
|
+
}
|
|
16503
|
+
}
|
|
16504
|
+
} catch {
|
|
16505
|
+
}
|
|
16506
|
+
}
|
|
16507
|
+
return {
|
|
16508
|
+
includeGlobs: [...new Set(globs)],
|
|
16509
|
+
negationPatterns: [...new Set(negations)]
|
|
16510
|
+
};
|
|
16511
|
+
}
|
|
16512
|
+
function parsePnpmWorkspaceYaml(content) {
|
|
16513
|
+
const lines = content.split("\n");
|
|
16514
|
+
const includeGlobs = [];
|
|
16515
|
+
const negationPatterns = [];
|
|
16516
|
+
let inPackages = false;
|
|
16517
|
+
for (const rawLine of lines) {
|
|
16518
|
+
const trimmed = rawLine.trim();
|
|
16519
|
+
if (/^packages\s*:/.test(trimmed)) {
|
|
16520
|
+
inPackages = true;
|
|
16521
|
+
continue;
|
|
16522
|
+
}
|
|
16523
|
+
if (inPackages && trimmed.length > 0 && !trimmed.startsWith("-") && !rawLine.startsWith(" ") && !rawLine.startsWith(" ")) {
|
|
16524
|
+
inPackages = false;
|
|
16525
|
+
continue;
|
|
16526
|
+
}
|
|
16527
|
+
if (!inPackages) continue;
|
|
16528
|
+
const itemMatch = /^\s*-\s+(.+)$/.exec(rawLine);
|
|
16529
|
+
if (!itemMatch) continue;
|
|
16530
|
+
const value = itemMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
16531
|
+
if (value.length === 0) continue;
|
|
16532
|
+
if (value.startsWith("!")) {
|
|
16533
|
+
negationPatterns.push(value.slice(1));
|
|
16534
|
+
continue;
|
|
16535
|
+
}
|
|
16536
|
+
includeGlobs.push(value);
|
|
16537
|
+
}
|
|
16538
|
+
return { includeGlobs, negationPatterns };
|
|
16539
|
+
}
|
|
16540
|
+
function parsePackageJsonWorkspaces(pkg) {
|
|
16541
|
+
const workspaces = pkg["workspaces"];
|
|
16542
|
+
if (workspaces === void 0 || workspaces === null) return [];
|
|
16543
|
+
if (Array.isArray(workspaces)) {
|
|
16544
|
+
return workspaces.filter((w) => typeof w === "string");
|
|
16545
|
+
}
|
|
16546
|
+
if (typeof workspaces === "object") {
|
|
16547
|
+
const obj = workspaces;
|
|
16548
|
+
const packages = obj["packages"];
|
|
16549
|
+
if (Array.isArray(packages)) {
|
|
16550
|
+
return packages.filter((p) => typeof p === "string");
|
|
16551
|
+
}
|
|
16552
|
+
}
|
|
16553
|
+
return [];
|
|
16554
|
+
}
|
|
16555
|
+
function expandGlobs(root, globs) {
|
|
16556
|
+
const dirs = [];
|
|
16557
|
+
for (const glob of globs) {
|
|
16558
|
+
const cleanGlob = glob.replace(/\/+$/, "");
|
|
16559
|
+
if (cleanGlob.includes("**")) {
|
|
16560
|
+
const prefix = cleanGlob.split("**")[0].replace(/\/+$/, "");
|
|
16561
|
+
const baseDir = path3.join(root, prefix);
|
|
16562
|
+
if (fs3.existsSync(baseDir)) {
|
|
16563
|
+
dirs.push(...walkDirectories(baseDir));
|
|
16564
|
+
}
|
|
16565
|
+
} else if (cleanGlob.includes("*")) {
|
|
16566
|
+
const parts = cleanGlob.split("*");
|
|
16567
|
+
const baseDir = path3.join(root, parts[0].replace(/\/+$/, ""));
|
|
16568
|
+
const suffix = parts.slice(1).join("*");
|
|
16569
|
+
if (!fs3.existsSync(baseDir)) continue;
|
|
16570
|
+
let entries;
|
|
16571
|
+
try {
|
|
16572
|
+
entries = fs3.readdirSync(baseDir, { withFileTypes: true });
|
|
16573
|
+
} catch {
|
|
16574
|
+
continue;
|
|
16575
|
+
}
|
|
16576
|
+
for (const entry of entries) {
|
|
16577
|
+
if (!entry.isDirectory()) continue;
|
|
16578
|
+
if (suffix && !entry.name.endsWith(suffix)) continue;
|
|
16579
|
+
dirs.push(path3.join(baseDir, entry.name));
|
|
16580
|
+
}
|
|
16581
|
+
} else {
|
|
16582
|
+
const targetDir = path3.join(root, cleanGlob);
|
|
16583
|
+
if (fs3.existsSync(targetDir) && fs3.statSync(targetDir).isDirectory()) {
|
|
16584
|
+
dirs.push(targetDir);
|
|
16585
|
+
}
|
|
16586
|
+
}
|
|
16587
|
+
}
|
|
16588
|
+
return dirs;
|
|
16589
|
+
}
|
|
16590
|
+
function walkDirectories(baseDir) {
|
|
16591
|
+
const result = [];
|
|
16592
|
+
let entries;
|
|
16593
|
+
try {
|
|
16594
|
+
entries = fs3.readdirSync(baseDir, { withFileTypes: true });
|
|
16595
|
+
} catch {
|
|
16596
|
+
return result;
|
|
16597
|
+
}
|
|
16598
|
+
for (const entry of entries) {
|
|
16599
|
+
if (!entry.isDirectory()) continue;
|
|
16600
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
16601
|
+
const fullPath = path3.join(baseDir, entry.name);
|
|
16602
|
+
if (fs3.existsSync(path3.join(fullPath, "package.json"))) {
|
|
16603
|
+
result.push(fullPath);
|
|
16604
|
+
}
|
|
16605
|
+
result.push(...walkDirectories(fullPath));
|
|
16606
|
+
}
|
|
16607
|
+
return result;
|
|
16608
|
+
}
|
|
16609
|
+
|
|
16610
|
+
// src/cli/init.ts
|
|
15764
16611
|
function meetsNodeVersion(minMajor) {
|
|
15765
16612
|
const [major] = process.versions.node.split(".").map(Number);
|
|
15766
16613
|
return major >= minMajor;
|
|
@@ -15787,32 +16634,43 @@ async function promptYesNo(question, defaultValue) {
|
|
|
15787
16634
|
});
|
|
15788
16635
|
}
|
|
15789
16636
|
async function runInit(options) {
|
|
15790
|
-
const {
|
|
16637
|
+
const { yes, coverageMap } = options;
|
|
15791
16638
|
const summary = [];
|
|
15792
16639
|
const warnings = [];
|
|
15793
16640
|
const errors = [];
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
16641
|
+
let projectRoot;
|
|
16642
|
+
try {
|
|
16643
|
+
const classification = resolveProjectRoot(options.projectRoot);
|
|
16644
|
+
projectRoot = classification.projectRoot;
|
|
16645
|
+
if (classification.isMonorepo && classification.appRelativePath) {
|
|
16646
|
+
summary.push(`Found Next.js app at ${classification.appRelativePath} \u2014 installing there`);
|
|
16647
|
+
}
|
|
16648
|
+
} catch (err) {
|
|
16649
|
+
errors.push(err instanceof Error ? err.message : String(err));
|
|
15797
16650
|
return { exitCode: 1, summary, warnings, errors };
|
|
15798
16651
|
}
|
|
15799
|
-
const
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
shouldWriteInstrumentation = await promptYesNo(
|
|
15804
|
-
"instrumentation.ts already exists. Overwrite?",
|
|
15805
|
-
false
|
|
15806
|
-
);
|
|
15807
|
-
} else if (instrumentationExists && yes) {
|
|
15808
|
-
shouldWriteInstrumentation = false;
|
|
16652
|
+
const packageJsonPath = path6.join(projectRoot, "package.json");
|
|
16653
|
+
if (!fs6.existsSync(packageJsonPath)) {
|
|
16654
|
+
errors.push("No package.json found. Run this command from a Node.js project root.");
|
|
16655
|
+
return { exitCode: 1, summary, warnings, errors };
|
|
15809
16656
|
}
|
|
15810
16657
|
try {
|
|
15811
|
-
const
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
|
|
16658
|
+
const instrResult = await scaffoldInstrumentation(projectRoot);
|
|
16659
|
+
switch (instrResult.action) {
|
|
16660
|
+
case "created":
|
|
16661
|
+
summary.push("Created instrumentation.ts");
|
|
16662
|
+
break;
|
|
16663
|
+
case "injected":
|
|
16664
|
+
summary.push("Added registerGlasstrace() to existing instrumentation.ts");
|
|
16665
|
+
break;
|
|
16666
|
+
case "already-registered":
|
|
16667
|
+
summary.push("Skipped instrumentation.ts (registerGlasstrace already present)");
|
|
16668
|
+
break;
|
|
16669
|
+
case "unrecognized":
|
|
16670
|
+
warnings.push(
|
|
16671
|
+
'instrumentation.ts exists but has no recognizable register() function.\nAdd this import at the top of your file:\n\n import { registerGlasstrace } from "@glasstrace/sdk";\n\nThen add this as the first statement in your register() function:\n\n registerGlasstrace();\n'
|
|
16672
|
+
);
|
|
16673
|
+
break;
|
|
15816
16674
|
}
|
|
15817
16675
|
} catch (err) {
|
|
15818
16676
|
errors.push(`Failed to write instrumentation.ts: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -15865,14 +16723,14 @@ async function runInit(options) {
|
|
|
15865
16723
|
if (isCI) {
|
|
15866
16724
|
const genericAgent = {
|
|
15867
16725
|
name: "generic",
|
|
15868
|
-
mcpConfigPath:
|
|
16726
|
+
mcpConfigPath: path6.join(projectRoot, ".glasstrace", "mcp.json"),
|
|
15869
16727
|
infoFilePath: null,
|
|
15870
16728
|
cliAvailable: false,
|
|
15871
16729
|
registrationCommand: null
|
|
15872
16730
|
};
|
|
15873
16731
|
const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
|
|
15874
16732
|
await writeMcpConfig(genericAgent, genericConfig, projectRoot);
|
|
15875
|
-
if (genericAgent.mcpConfigPath !== null &&
|
|
16733
|
+
if (genericAgent.mcpConfigPath !== null && fs6.existsSync(genericAgent.mcpConfigPath)) {
|
|
15876
16734
|
anyConfigWritten = true;
|
|
15877
16735
|
summary.push("Created .glasstrace/mcp.json (CI mode)");
|
|
15878
16736
|
}
|
|
@@ -15886,14 +16744,14 @@ async function runInit(options) {
|
|
|
15886
16744
|
);
|
|
15887
16745
|
const genericAgent = {
|
|
15888
16746
|
name: "generic",
|
|
15889
|
-
mcpConfigPath:
|
|
16747
|
+
mcpConfigPath: path6.join(projectRoot, ".glasstrace", "mcp.json"),
|
|
15890
16748
|
infoFilePath: null,
|
|
15891
16749
|
cliAvailable: false,
|
|
15892
16750
|
registrationCommand: null
|
|
15893
16751
|
};
|
|
15894
16752
|
const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
|
|
15895
16753
|
await writeMcpConfig(genericAgent, genericConfig, projectRoot);
|
|
15896
|
-
if (genericAgent.mcpConfigPath !== null &&
|
|
16754
|
+
if (genericAgent.mcpConfigPath !== null && fs6.existsSync(genericAgent.mcpConfigPath)) {
|
|
15897
16755
|
anyConfigWritten = true;
|
|
15898
16756
|
}
|
|
15899
16757
|
agents = [];
|
|
@@ -15903,7 +16761,7 @@ async function runInit(options) {
|
|
|
15903
16761
|
try {
|
|
15904
16762
|
const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);
|
|
15905
16763
|
await writeMcpConfig(agent, configContent, projectRoot);
|
|
15906
|
-
const configExists = agent.mcpConfigPath !== null &&
|
|
16764
|
+
const configExists = agent.mcpConfigPath !== null && fs6.existsSync(agent.mcpConfigPath);
|
|
15907
16765
|
if (!configExists) {
|
|
15908
16766
|
continue;
|
|
15909
16767
|
}
|
|
@@ -15990,7 +16848,7 @@ function parseArgs(argv) {
|
|
|
15990
16848
|
};
|
|
15991
16849
|
}
|
|
15992
16850
|
var scriptPath = typeof process !== "undefined" && process.argv[1] !== void 0 ? process.argv[1].replace(/\\/g, "/") : void 0;
|
|
15993
|
-
var scriptBasename = scriptPath !== void 0 ?
|
|
16851
|
+
var scriptBasename = scriptPath !== void 0 ? path6.basename(scriptPath) : void 0;
|
|
15994
16852
|
var isDirectExecution = scriptPath !== void 0 && (scriptPath.endsWith("/cli/init.js") || scriptPath.endsWith("/cli/init.ts") || scriptBasename === "glasstrace");
|
|
15995
16853
|
if (isDirectExecution) {
|
|
15996
16854
|
if (!meetsNodeVersion(20)) {
|
|
@@ -16061,6 +16919,38 @@ Usage: glasstrace mcp add [--force] [--dry-run]
|
|
|
16061
16919
|
}).catch((err) => {
|
|
16062
16920
|
process.stderr.write(
|
|
16063
16921
|
`Fatal error: ${err instanceof Error ? err.message : String(err)}
|
|
16922
|
+
`
|
|
16923
|
+
);
|
|
16924
|
+
process.exit(1);
|
|
16925
|
+
});
|
|
16926
|
+
} else if (subcommand === "uninit") {
|
|
16927
|
+
const remainingArgs = process.argv.slice(3);
|
|
16928
|
+
const dryRun = remainingArgs.includes("--dry-run");
|
|
16929
|
+
Promise.resolve().then(() => (init_uninit(), uninit_exports)).then(({ runUninit: runUninit2 }) => runUninit2({ projectRoot: process.cwd(), dryRun })).then((result) => {
|
|
16930
|
+
if (result.errors.length > 0) {
|
|
16931
|
+
for (const err of result.errors) {
|
|
16932
|
+
process.stderr.write(`Error: ${err}
|
|
16933
|
+
`);
|
|
16934
|
+
}
|
|
16935
|
+
}
|
|
16936
|
+
if (result.warnings.length > 0) {
|
|
16937
|
+
for (const warn of result.warnings) {
|
|
16938
|
+
process.stderr.write(`Warning: ${warn}
|
|
16939
|
+
`);
|
|
16940
|
+
}
|
|
16941
|
+
}
|
|
16942
|
+
if (result.summary.length > 0) {
|
|
16943
|
+
process.stderr.write("\n");
|
|
16944
|
+
for (const line of result.summary) {
|
|
16945
|
+
process.stderr.write(` ${line}
|
|
16946
|
+
`);
|
|
16947
|
+
}
|
|
16948
|
+
process.stderr.write("\n");
|
|
16949
|
+
}
|
|
16950
|
+
process.exit(result.exitCode);
|
|
16951
|
+
}).catch((err) => {
|
|
16952
|
+
process.stderr.write(
|
|
16953
|
+
`Fatal error: ${err instanceof Error ? err.message : String(err)}
|
|
16064
16954
|
`
|
|
16065
16955
|
);
|
|
16066
16956
|
process.exit(1);
|
|
@@ -16071,6 +16961,7 @@ Usage: glasstrace mcp add [--force] [--dry-run]
|
|
|
16071
16961
|
|
|
16072
16962
|
Usage:
|
|
16073
16963
|
glasstrace init [--yes] [--coverage-map]
|
|
16964
|
+
glasstrace uninit [--dry-run]
|
|
16074
16965
|
glasstrace mcp add [--force] [--dry-run]
|
|
16075
16966
|
`
|
|
16076
16967
|
);
|