@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/mcp-add.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
-
MCP_ENDPOINT,
|
|
3
2
|
detectAgents,
|
|
4
|
-
formatAgentName,
|
|
5
3
|
generateInfoSection,
|
|
6
4
|
generateMcpConfig,
|
|
7
5
|
injectInfoSection,
|
|
8
6
|
scaffoldMcpMarker,
|
|
9
7
|
updateGitignore,
|
|
10
8
|
writeMcpConfig
|
|
11
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-4NDQPWDJ.js";
|
|
12
10
|
import {
|
|
13
11
|
readAnonKey
|
|
14
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-PQWAKVQ5.js";
|
|
13
|
+
import {
|
|
14
|
+
MCP_ENDPOINT,
|
|
15
|
+
formatAgentName
|
|
16
|
+
} from "../chunk-DXRZKKSO.js";
|
|
15
17
|
import "../chunk-PZ5AY32C.js";
|
|
16
18
|
|
|
17
19
|
// src/cli/mcp-add.ts
|
package/dist/cli/mcp-add.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/mcp-add.ts"],"sourcesContent":["import { execFile as execFileCb } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { readAnonKey } from \"../anon-key.js\";\nimport { detectAgents } from \"../agent-detection/detect.js\";\nimport { generateMcpConfig, generateInfoSection } from \"../agent-detection/configs.js\";\nimport {\n writeMcpConfig,\n injectInfoSection,\n updateGitignore,\n} from \"../agent-detection/inject.js\";\nimport { scaffoldMcpMarker } from \"./scaffolder.js\";\nimport type { DetectedAgent } from \"../agent-detection/detect.js\";\nimport { MCP_ENDPOINT, formatAgentName } from \"./constants.js\";\n\nconst execFileAsync = promisify(execFileCb);\n\n/** Options for the mcp add command. */\nexport interface McpAddOptions {\n force?: boolean;\n dryRun?: boolean;\n}\n\n/** Result of the mcp add command. */\nexport interface McpAddResult {\n exitCode: number;\n results: AgentResult[];\n messages: string[];\n}\n\n/**\n * Result of a single agent registration attempt.\n */\ninterface AgentResult {\n agent: DetectedAgent[\"name\"];\n success: boolean;\n method: \"cli\" | \"file\" | \"skipped\";\n message: string;\n}\n\n/**\n * Attempts CLI-based MCP registration for agents that support it.\n * Returns true if the CLI command succeeded.\n *\n * Note: anonymous keys are passed in process arguments for CLI registration.\n * This is acceptable because anon keys are non-secret identifiers (not\n * credentials) designed for semi-public use. They identify a project\n * but cannot be used to access user data.\n */\nasync function registerViaCli(\n agent: DetectedAgent,\n anonKey: string,\n): Promise<boolean> {\n if (!agent.cliAvailable) {\n return false;\n }\n\n try {\n switch (agent.name) {\n case \"claude\": {\n const payload = JSON.stringify({\n type: \"http\",\n url: MCP_ENDPOINT,\n headers: { Authorization: `Bearer ${anonKey}` },\n });\n await execFileAsync(\"claude\", [\n \"mcp\",\n \"add-json\",\n \"glasstrace\",\n payload,\n \"--scope\",\n \"project\",\n ]);\n return true;\n }\n\n case \"codex\": {\n await execFileAsync(\"codex\", [\n \"mcp\",\n \"add\",\n \"glasstrace\",\n \"--url\",\n MCP_ENDPOINT,\n ]);\n // Ensure .codex/config.toml has bearer_token_env_var\n const configPath = agent.mcpConfigPath;\n if (configPath !== null && fs.existsSync(configPath)) {\n const content = fs.readFileSync(configPath, \"utf-8\");\n if (!content.includes(\"bearer_token_env_var\")) {\n const appendContent =\n content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n fs.writeFileSync(\n configPath,\n content +\n appendContent +\n 'bearer_token_env_var = \"GLASSTRACE_API_KEY\"\\n',\n \"utf-8\",\n );\n }\n }\n process.stderr.write(\n \" Note: Set GLASSTRACE_API_KEY environment variable for Codex authentication.\\n\",\n );\n return true;\n }\n\n case \"gemini\": {\n await execFileAsync(\"gemini\", [\n \"mcp\",\n \"add\",\n \"--transport\",\n \"http\",\n \"--header\",\n `Authorization: Bearer ${anonKey}`,\n \"glasstrace\",\n MCP_ENDPOINT,\n ]);\n return true;\n }\n\n default:\n return false;\n }\n } catch {\n return false;\n }\n}\n\n/**\n * Registers the Glasstrace MCP server with detected AI coding agents.\n *\n * For each agent, attempts native CLI registration first, then falls back\n * to file-based configuration. Creates a marker file on success to enable\n * idempotent re-runs.\n *\n * Returns a structured result instead of calling process.exit(), so the\n * CLI entry point can decide how to handle the outcome.\n *\n * @param options - Control flags for force and dry-run modes.\n */\nexport async function mcpAdd(options?: McpAddOptions): Promise<McpAddResult> {\n const force = options?.force ?? false;\n const dryRun = options?.dryRun ?? false;\n const projectRoot = process.cwd();\n const messages: string[] = [];\n\n // Step 1: Read anon key\n const anonKey = await readAnonKey(projectRoot);\n if (anonKey === null) {\n return {\n exitCode: 1,\n results: [],\n messages: [\"Error: Run `glasstrace init` first to generate an API key.\"],\n };\n }\n\n // Step 2: Check marker file\n const markerPath = path.join(projectRoot, \".glasstrace\", \"mcp-connected\");\n if (fs.existsSync(markerPath) && !force) {\n return {\n exitCode: 0,\n results: [],\n messages: [\"MCP already configured. Use --force to reconfigure.\"],\n };\n }\n\n // Step 3: Detect agents\n const agents = await detectAgents(projectRoot);\n const detectedNonGeneric = agents.filter((a) => a.name !== \"generic\");\n\n // If no specific agents found, include the generic fallback so the command\n // still produces a usable .glasstrace/mcp.json (matching init behavior).\n const targetAgents =\n detectedNonGeneric.length > 0\n ? detectedNonGeneric\n : agents.filter((a) => a.name === \"generic\");\n\n if (dryRun) {\n messages.push(\"Dry run: would perform the following actions:\", \"\");\n for (const agent of targetAgents) {\n const name = formatAgentName(agent.name);\n if (agent.cliAvailable) {\n messages.push(\n ` ${name}: Register via CLI (${agent.name} mcp add)`,\n );\n } else if (agent.mcpConfigPath !== null) {\n messages.push(\n ` ${name}: Write config to ${agent.mcpConfigPath}`,\n );\n }\n if (agent.infoFilePath !== null) {\n messages.push(\n ` ${name}: Inject info section into ${agent.infoFilePath}`,\n );\n }\n }\n messages.push(\n \"\",\n \" Update .gitignore with MCP config paths\",\n \" Create .glasstrace/mcp-connected marker\",\n );\n return { exitCode: 0, results: [], messages };\n }\n\n // Step 4: Register with each agent\n const results: AgentResult[] = [];\n\n for (const agent of targetAgents) {\n const name = formatAgentName(agent.name);\n\n // Try CLI registration first (not applicable for generic)\n if (agent.name !== \"generic\") {\n const cliSuccess = await registerViaCli(agent, anonKey);\n if (cliSuccess) {\n // Still inject info section if applicable\n const infoContent = generateInfoSection(agent, MCP_ENDPOINT);\n if (infoContent !== \"\") {\n await injectInfoSection(agent, infoContent, projectRoot);\n }\n results.push({\n agent: agent.name,\n success: true,\n method: \"cli\",\n message: `${name}: Registered via CLI`,\n });\n continue;\n }\n }\n\n // Fall back to file-based config\n if (agent.mcpConfigPath !== null) {\n try {\n const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);\n await writeMcpConfig(agent, configContent, projectRoot);\n\n // Verify the config was written (writeMcpConfig swallows permission errors)\n if (fs.existsSync(agent.mcpConfigPath)) {\n const infoContent = generateInfoSection(agent, MCP_ENDPOINT);\n if (infoContent !== \"\") {\n await injectInfoSection(agent, infoContent, projectRoot);\n }\n results.push({\n agent: agent.name,\n success: true,\n method: \"file\",\n message: `${name}: Configured via ${agent.mcpConfigPath}`,\n });\n continue;\n }\n\n // writeMcpConfig returned without throwing but file doesn't exist\n // (permission denied handled gracefully inside writeMcpConfig)\n results.push({\n agent: agent.name,\n success: false,\n method: \"file\",\n message: `${name}: Failed to write config to ${agent.mcpConfigPath} (permission denied)`,\n });\n continue;\n } catch (err) {\n results.push({\n agent: agent.name,\n success: false,\n method: \"file\",\n message: `${name}: Failed - ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n }\n\n results.push({\n agent: agent.name,\n success: false,\n method: \"skipped\",\n message: `${name}: No registration method available`,\n });\n }\n\n // Step 5: Update gitignore\n await updateGitignore(\n [\".mcp.json\", \".cursor/mcp.json\", \".gemini/settings.json\", \".codex/config.toml\"],\n projectRoot,\n );\n\n // Step 6: Create marker file if at least one succeeded\n const anySuccess = results.some((r) => r.success);\n\n if (anySuccess) {\n await scaffoldMcpMarker(projectRoot, anonKey);\n }\n\n // Step 7: Build summary messages\n messages.push(\"\", \"MCP registration summary:\");\n for (const result of results) {\n const icon = result.success ? \"+\" : \"-\";\n messages.push(` [${icon}] ${result.message}`);\n }\n\n if (results.length === 0) {\n messages.push(\n \" No agents detected. Place agent marker files (e.g., CLAUDE.md, .cursor/) in your project.\",\n );\n }\n\n if (!anySuccess && results.length > 0) {\n messages.push(\n \"\",\n \"All agent registrations failed. Check errors above.\",\n );\n return { exitCode: 1, results, messages };\n }\n\n if (anySuccess) {\n messages.push(\"\", \"MCP registration complete.\");\n }\n\n return { exitCode: 0, results, messages };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,kBAAkB;AACvC,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,iBAAiB;AAa1B,IAAM,gBAAgB,UAAU,UAAU;AAkC1C,eAAe,eACb,OACA,SACkB;AAClB,MAAI,CAAC,MAAM,cAAc;AACvB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,UAAU;AACb,cAAM,UAAU,KAAK,UAAU;AAAA,UAC7B,MAAM;AAAA,UACN,KAAK;AAAA,UACL,SAAS,EAAE,eAAe,UAAU,OAAO,GAAG;AAAA,QAChD,CAAC;AACD,cAAM,cAAc,UAAU;AAAA,UAC5B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AACD,eAAO;AAAA,MACT;AAAA,MAEA,KAAK,SAAS;AACZ,cAAM,cAAc,SAAS;AAAA,UAC3B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM,aAAa,MAAM;AACzB,YAAI,eAAe,QAAW,cAAW,UAAU,GAAG;AACpD,gBAAM,UAAa,gBAAa,YAAY,OAAO;AACnD,cAAI,CAAC,QAAQ,SAAS,sBAAsB,GAAG;AAC7C,kBAAM,gBACJ,QAAQ,SAAS,IAAI,IAAI,KAAK;AAChC,YAAG;AAAA,cACD;AAAA,cACA,UACE,gBACA;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,KAAK,UAAU;AACb,cAAM,cAAc,UAAU;AAAA,UAC5B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,yBAAyB,OAAO;AAAA,UAChC;AAAA,UACA;AAAA,QACF,CAAC;AACD,eAAO;AAAA,MACT;AAAA,MAEA;AACE,eAAO;AAAA,IACX;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAcA,eAAsB,OAAO,SAAgD;AAC3E,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,cAAc,QAAQ,IAAI;AAChC,QAAM,WAAqB,CAAC;AAG5B,QAAM,UAAU,MAAM,YAAY,WAAW;AAC7C,MAAI,YAAY,MAAM;AACpB,WAAO;AAAA,MACL,UAAU;AAAA,MACV,SAAS,CAAC;AAAA,MACV,UAAU,CAAC,4DAA4D;AAAA,IACzE;AAAA,EACF;AAGA,QAAM,aAAkB,UAAK,aAAa,eAAe,eAAe;AACxE,MAAO,cAAW,UAAU,KAAK,CAAC,OAAO;AACvC,WAAO;AAAA,MACL,UAAU;AAAA,MACV,SAAS,CAAC;AAAA,MACV,UAAU,CAAC,qDAAqD;AAAA,IAClE;AAAA,EACF;AAGA,QAAM,SAAS,MAAM,aAAa,WAAW;AAC7C,QAAM,qBAAqB,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAIpE,QAAM,eACJ,mBAAmB,SAAS,IACxB,qBACA,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAE/C,MAAI,QAAQ;AACV,aAAS,KAAK,iDAAiD,EAAE;AACjE,eAAW,SAAS,cAAc;AAChC,YAAM,OAAO,gBAAgB,MAAM,IAAI;AACvC,UAAI,MAAM,cAAc;AACtB,iBAAS;AAAA,UACP,KAAK,IAAI,uBAAuB,MAAM,IAAI;AAAA,QAC5C;AAAA,MACF,WAAW,MAAM,kBAAkB,MAAM;AACvC,iBAAS;AAAA,UACP,KAAK,IAAI,qBAAqB,MAAM,aAAa;AAAA,QACnD;AAAA,MACF;AACA,UAAI,MAAM,iBAAiB,MAAM;AAC/B,iBAAS;AAAA,UACP,KAAK,IAAI,8BAA8B,MAAM,YAAY;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AACA,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,UAAU,GAAG,SAAS,CAAC,GAAG,SAAS;AAAA,EAC9C;AAGA,QAAM,UAAyB,CAAC;AAEhC,aAAW,SAAS,cAAc;AAChC,UAAM,OAAO,gBAAgB,MAAM,IAAI;AAGvC,QAAI,MAAM,SAAS,WAAW;AAC5B,YAAM,aAAa,MAAM,eAAe,OAAO,OAAO;AACtD,UAAI,YAAY;AAEd,cAAM,cAAc,oBAAoB,OAAO,YAAY;AAC3D,YAAI,gBAAgB,IAAI;AACtB,gBAAM,kBAAkB,OAAO,aAAa,WAAW;AAAA,QACzD;AACA,gBAAQ,KAAK;AAAA,UACX,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,SAAS,GAAG,IAAI;AAAA,QAClB,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM,kBAAkB,MAAM;AAChC,UAAI;AACF,cAAM,gBAAgB,kBAAkB,OAAO,cAAc,OAAO;AACpE,cAAM,eAAe,OAAO,eAAe,WAAW;AAGtD,YAAO,cAAW,MAAM,aAAa,GAAG;AACtC,gBAAM,cAAc,oBAAoB,OAAO,YAAY;AAC3D,cAAI,gBAAgB,IAAI;AACtB,kBAAM,kBAAkB,OAAO,aAAa,WAAW;AAAA,UACzD;AACA,kBAAQ,KAAK;AAAA,YACX,OAAO,MAAM;AAAA,YACb,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,SAAS,GAAG,IAAI,oBAAoB,MAAM,aAAa;AAAA,UACzD,CAAC;AACD;AAAA,QACF;AAIA,gBAAQ,KAAK;AAAA,UACX,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,SAAS,GAAG,IAAI,+BAA+B,MAAM,aAAa;AAAA,QACpE,CAAC;AACD;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,KAAK;AAAA,UACX,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,SAAS,GAAG,IAAI,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAChF,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,OAAO,MAAM;AAAA,MACb,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS,GAAG,IAAI;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,QAAM;AAAA,IACJ,CAAC,aAAa,oBAAoB,yBAAyB,oBAAoB;AAAA,IAC/E;AAAA,EACF;AAGA,QAAM,aAAa,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO;AAEhD,MAAI,YAAY;AACd,UAAM,kBAAkB,aAAa,OAAO;AAAA,EAC9C;AAGA,WAAS,KAAK,IAAI,2BAA2B;AAC7C,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,OAAO,UAAU,MAAM;AACpC,aAAS,KAAK,MAAM,IAAI,KAAK,OAAO,OAAO,EAAE;AAAA,EAC/C;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,cAAc,QAAQ,SAAS,GAAG;AACrC,aAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,UAAU,GAAG,SAAS,SAAS;AAAA,EAC1C;AAEA,MAAI,YAAY;AACd,aAAS,KAAK,IAAI,4BAA4B;AAAA,EAChD;AAEA,SAAO,EAAE,UAAU,GAAG,SAAS,SAAS;AAC1C;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/mcp-add.ts"],"sourcesContent":["import { execFile as execFileCb } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { readAnonKey } from \"../anon-key.js\";\nimport { detectAgents } from \"../agent-detection/detect.js\";\nimport { generateMcpConfig, generateInfoSection } from \"../agent-detection/configs.js\";\nimport {\n writeMcpConfig,\n injectInfoSection,\n updateGitignore,\n} from \"../agent-detection/inject.js\";\nimport { scaffoldMcpMarker } from \"./scaffolder.js\";\nimport type { DetectedAgent } from \"../agent-detection/detect.js\";\nimport { MCP_ENDPOINT, formatAgentName } from \"./constants.js\";\n\nconst execFileAsync = promisify(execFileCb);\n\n/** Options for the mcp add command. */\nexport interface McpAddOptions {\n force?: boolean;\n dryRun?: boolean;\n}\n\n/** Result of the mcp add command. */\nexport interface McpAddResult {\n exitCode: number;\n results: AgentResult[];\n messages: string[];\n}\n\n/**\n * Result of a single agent registration attempt.\n */\ninterface AgentResult {\n agent: DetectedAgent[\"name\"];\n success: boolean;\n method: \"cli\" | \"file\" | \"skipped\";\n message: string;\n}\n\n/**\n * Attempts CLI-based MCP registration for agents that support it.\n * Returns true if the CLI command succeeded.\n *\n * Note: anonymous keys are passed in process arguments for CLI registration.\n * This is acceptable because anon keys are non-secret identifiers (not\n * credentials) designed for semi-public use. They identify a project\n * but cannot be used to access user data.\n */\nasync function registerViaCli(\n agent: DetectedAgent,\n anonKey: string,\n): Promise<boolean> {\n if (!agent.cliAvailable) {\n return false;\n }\n\n try {\n switch (agent.name) {\n case \"claude\": {\n const payload = JSON.stringify({\n type: \"http\",\n url: MCP_ENDPOINT,\n headers: { Authorization: `Bearer ${anonKey}` },\n });\n await execFileAsync(\"claude\", [\n \"mcp\",\n \"add-json\",\n \"glasstrace\",\n payload,\n \"--scope\",\n \"project\",\n ]);\n return true;\n }\n\n case \"codex\": {\n await execFileAsync(\"codex\", [\n \"mcp\",\n \"add\",\n \"glasstrace\",\n \"--url\",\n MCP_ENDPOINT,\n ]);\n // Ensure .codex/config.toml has bearer_token_env_var\n const configPath = agent.mcpConfigPath;\n if (configPath !== null && fs.existsSync(configPath)) {\n const content = fs.readFileSync(configPath, \"utf-8\");\n if (!content.includes(\"bearer_token_env_var\")) {\n const appendContent =\n content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n fs.writeFileSync(\n configPath,\n content +\n appendContent +\n 'bearer_token_env_var = \"GLASSTRACE_API_KEY\"\\n',\n \"utf-8\",\n );\n }\n }\n process.stderr.write(\n \" Note: Set GLASSTRACE_API_KEY environment variable for Codex authentication.\\n\",\n );\n return true;\n }\n\n case \"gemini\": {\n await execFileAsync(\"gemini\", [\n \"mcp\",\n \"add\",\n \"--transport\",\n \"http\",\n \"--header\",\n `Authorization: Bearer ${anonKey}`,\n \"glasstrace\",\n MCP_ENDPOINT,\n ]);\n return true;\n }\n\n default:\n return false;\n }\n } catch {\n return false;\n }\n}\n\n/**\n * Registers the Glasstrace MCP server with detected AI coding agents.\n *\n * For each agent, attempts native CLI registration first, then falls back\n * to file-based configuration. Creates a marker file on success to enable\n * idempotent re-runs.\n *\n * Returns a structured result instead of calling process.exit(), so the\n * CLI entry point can decide how to handle the outcome.\n *\n * @param options - Control flags for force and dry-run modes.\n */\nexport async function mcpAdd(options?: McpAddOptions): Promise<McpAddResult> {\n const force = options?.force ?? false;\n const dryRun = options?.dryRun ?? false;\n const projectRoot = process.cwd();\n const messages: string[] = [];\n\n // Step 1: Read anon key\n const anonKey = await readAnonKey(projectRoot);\n if (anonKey === null) {\n return {\n exitCode: 1,\n results: [],\n messages: [\"Error: Run `glasstrace init` first to generate an API key.\"],\n };\n }\n\n // Step 2: Check marker file\n const markerPath = path.join(projectRoot, \".glasstrace\", \"mcp-connected\");\n if (fs.existsSync(markerPath) && !force) {\n return {\n exitCode: 0,\n results: [],\n messages: [\"MCP already configured. Use --force to reconfigure.\"],\n };\n }\n\n // Step 3: Detect agents\n const agents = await detectAgents(projectRoot);\n const detectedNonGeneric = agents.filter((a) => a.name !== \"generic\");\n\n // If no specific agents found, include the generic fallback so the command\n // still produces a usable .glasstrace/mcp.json (matching init behavior).\n const targetAgents =\n detectedNonGeneric.length > 0\n ? detectedNonGeneric\n : agents.filter((a) => a.name === \"generic\");\n\n if (dryRun) {\n messages.push(\"Dry run: would perform the following actions:\", \"\");\n for (const agent of targetAgents) {\n const name = formatAgentName(agent.name);\n if (agent.cliAvailable) {\n messages.push(\n ` ${name}: Register via CLI (${agent.name} mcp add)`,\n );\n } else if (agent.mcpConfigPath !== null) {\n messages.push(\n ` ${name}: Write config to ${agent.mcpConfigPath}`,\n );\n }\n if (agent.infoFilePath !== null) {\n messages.push(\n ` ${name}: Inject info section into ${agent.infoFilePath}`,\n );\n }\n }\n messages.push(\n \"\",\n \" Update .gitignore with MCP config paths\",\n \" Create .glasstrace/mcp-connected marker\",\n );\n return { exitCode: 0, results: [], messages };\n }\n\n // Step 4: Register with each agent\n const results: AgentResult[] = [];\n\n for (const agent of targetAgents) {\n const name = formatAgentName(agent.name);\n\n // Try CLI registration first (not applicable for generic)\n if (agent.name !== \"generic\") {\n const cliSuccess = await registerViaCli(agent, anonKey);\n if (cliSuccess) {\n // Still inject info section if applicable\n const infoContent = generateInfoSection(agent, MCP_ENDPOINT);\n if (infoContent !== \"\") {\n await injectInfoSection(agent, infoContent, projectRoot);\n }\n results.push({\n agent: agent.name,\n success: true,\n method: \"cli\",\n message: `${name}: Registered via CLI`,\n });\n continue;\n }\n }\n\n // Fall back to file-based config\n if (agent.mcpConfigPath !== null) {\n try {\n const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);\n await writeMcpConfig(agent, configContent, projectRoot);\n\n // Verify the config was written (writeMcpConfig swallows permission errors)\n if (fs.existsSync(agent.mcpConfigPath)) {\n const infoContent = generateInfoSection(agent, MCP_ENDPOINT);\n if (infoContent !== \"\") {\n await injectInfoSection(agent, infoContent, projectRoot);\n }\n results.push({\n agent: agent.name,\n success: true,\n method: \"file\",\n message: `${name}: Configured via ${agent.mcpConfigPath}`,\n });\n continue;\n }\n\n // writeMcpConfig returned without throwing but file doesn't exist\n // (permission denied handled gracefully inside writeMcpConfig)\n results.push({\n agent: agent.name,\n success: false,\n method: \"file\",\n message: `${name}: Failed to write config to ${agent.mcpConfigPath} (permission denied)`,\n });\n continue;\n } catch (err) {\n results.push({\n agent: agent.name,\n success: false,\n method: \"file\",\n message: `${name}: Failed - ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n }\n\n results.push({\n agent: agent.name,\n success: false,\n method: \"skipped\",\n message: `${name}: No registration method available`,\n });\n }\n\n // Step 5: Update gitignore\n await updateGitignore(\n [\".mcp.json\", \".cursor/mcp.json\", \".gemini/settings.json\", \".codex/config.toml\"],\n projectRoot,\n );\n\n // Step 6: Create marker file if at least one succeeded\n const anySuccess = results.some((r) => r.success);\n\n if (anySuccess) {\n await scaffoldMcpMarker(projectRoot, anonKey);\n }\n\n // Step 7: Build summary messages\n messages.push(\"\", \"MCP registration summary:\");\n for (const result of results) {\n const icon = result.success ? \"+\" : \"-\";\n messages.push(` [${icon}] ${result.message}`);\n }\n\n if (results.length === 0) {\n messages.push(\n \" No agents detected. Place agent marker files (e.g., CLAUDE.md, .cursor/) in your project.\",\n );\n }\n\n if (!anySuccess && results.length > 0) {\n messages.push(\n \"\",\n \"All agent registrations failed. Check errors above.\",\n );\n return { exitCode: 1, results, messages };\n }\n\n if (anySuccess) {\n messages.push(\"\", \"MCP registration complete.\");\n }\n\n return { exitCode: 0, results, messages };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/cli/uninit.ts
|
|
31
|
+
var uninit_exports = {};
|
|
32
|
+
__export(uninit_exports, {
|
|
33
|
+
findMatchingParen: () => findMatchingParen,
|
|
34
|
+
isInitCreatedInstrumentation: () => isInitCreatedInstrumentation,
|
|
35
|
+
processJsonMcpConfig: () => processJsonMcpConfig,
|
|
36
|
+
processTomlMcpConfig: () => processTomlMcpConfig,
|
|
37
|
+
removeGlasstraceConfigImport: () => removeGlasstraceConfigImport,
|
|
38
|
+
removeMarkerSection: () => removeMarkerSection,
|
|
39
|
+
removeRegisterGlasstrace: () => removeRegisterGlasstrace,
|
|
40
|
+
runUninit: () => runUninit,
|
|
41
|
+
unwrapCJSExport: () => unwrapCJSExport,
|
|
42
|
+
unwrapExport: () => unwrapExport
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(uninit_exports);
|
|
45
|
+
var fs = __toESM(require("fs"), 1);
|
|
46
|
+
var os = __toESM(require("os"), 1);
|
|
47
|
+
var path = __toESM(require("path"), 1);
|
|
48
|
+
|
|
49
|
+
// src/cli/constants.ts
|
|
50
|
+
var NEXT_CONFIG_NAMES = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
51
|
+
|
|
52
|
+
// src/cli/uninit.ts
|
|
53
|
+
var MCP_CONFIG_FILES = [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json"];
|
|
54
|
+
var AGENT_INFO_FILES = [
|
|
55
|
+
"CLAUDE.md",
|
|
56
|
+
"codex.md",
|
|
57
|
+
".cursorrules"
|
|
58
|
+
];
|
|
59
|
+
function findMatchingParen(text, openPos) {
|
|
60
|
+
let depth = 0;
|
|
61
|
+
for (let i = openPos; i < text.length; i++) {
|
|
62
|
+
if (text[i] === "(") {
|
|
63
|
+
depth++;
|
|
64
|
+
} else if (text[i] === ")") {
|
|
65
|
+
depth--;
|
|
66
|
+
if (depth === 0) {
|
|
67
|
+
return i;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
73
|
+
function unwrapExport(content) {
|
|
74
|
+
const pattern = /export\s+default\s+withGlasstraceConfig\s*\(/;
|
|
75
|
+
const match = pattern.exec(content);
|
|
76
|
+
if (!match) {
|
|
77
|
+
return { content, unwrapped: false };
|
|
78
|
+
}
|
|
79
|
+
const openParenIdx = match.index + match[0].length - 1;
|
|
80
|
+
const closeParenIdx = findMatchingParen(content, openParenIdx);
|
|
81
|
+
if (closeParenIdx === -1) {
|
|
82
|
+
return { content, unwrapped: false };
|
|
83
|
+
}
|
|
84
|
+
const innerExpr = content.slice(openParenIdx + 1, closeParenIdx).trim();
|
|
85
|
+
if (innerExpr.length === 0) {
|
|
86
|
+
return { content, unwrapped: false };
|
|
87
|
+
}
|
|
88
|
+
const before = content.slice(0, match.index);
|
|
89
|
+
const afterClose = content.slice(closeParenIdx + 1);
|
|
90
|
+
const trailing = afterClose.replace(/^;?\s*/, "");
|
|
91
|
+
const result = before + `export default ${innerExpr};
|
|
92
|
+
` + trailing;
|
|
93
|
+
return { content: result, unwrapped: true };
|
|
94
|
+
}
|
|
95
|
+
function unwrapCJSExport(content) {
|
|
96
|
+
const pattern = /module\.exports\s*=\s*withGlasstraceConfig\s*\(/;
|
|
97
|
+
const match = pattern.exec(content);
|
|
98
|
+
if (!match) {
|
|
99
|
+
return { content, unwrapped: false };
|
|
100
|
+
}
|
|
101
|
+
const openParenIdx = match.index + match[0].length - 1;
|
|
102
|
+
const closeParenIdx = findMatchingParen(content, openParenIdx);
|
|
103
|
+
if (closeParenIdx === -1) {
|
|
104
|
+
return { content, unwrapped: false };
|
|
105
|
+
}
|
|
106
|
+
const innerExpr = content.slice(openParenIdx + 1, closeParenIdx).trim();
|
|
107
|
+
if (innerExpr.length === 0) {
|
|
108
|
+
return { content, unwrapped: false };
|
|
109
|
+
}
|
|
110
|
+
const before = content.slice(0, match.index);
|
|
111
|
+
const afterClose = content.slice(closeParenIdx + 1);
|
|
112
|
+
const trailing = afterClose.replace(/^;?\s*/, "");
|
|
113
|
+
const result = before + `module.exports = ${innerExpr};
|
|
114
|
+
` + trailing;
|
|
115
|
+
return { content: result, unwrapped: true };
|
|
116
|
+
}
|
|
117
|
+
function removeGlasstraceConfigImport(content) {
|
|
118
|
+
const esmSoleImport = /import\s*\{\s*withGlasstraceConfig\s*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/;
|
|
119
|
+
if (esmSoleImport.test(content)) {
|
|
120
|
+
return content.replace(esmSoleImport, "");
|
|
121
|
+
}
|
|
122
|
+
const esmMultiImport = /import\s*\{([^}]*)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
123
|
+
const multiMatch = esmMultiImport.exec(content);
|
|
124
|
+
if (multiMatch) {
|
|
125
|
+
const specifiers = multiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "withGlasstraceConfig");
|
|
126
|
+
if (specifiers.length === 0) {
|
|
127
|
+
return content.replace(
|
|
128
|
+
/import\s*\{[^}]*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/,
|
|
129
|
+
""
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
const newImport = `import { ${specifiers.join(", ")} } from "@glasstrace/sdk"`;
|
|
133
|
+
return content.replace(multiMatch[0], newImport);
|
|
134
|
+
}
|
|
135
|
+
const cjsSoleRequire = /const\s*\{\s*withGlasstraceConfig\s*\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)\s*;?\s*\n?/;
|
|
136
|
+
if (cjsSoleRequire.test(content)) {
|
|
137
|
+
return content.replace(cjsSoleRequire, "");
|
|
138
|
+
}
|
|
139
|
+
const cjsMultiRequire = /const\s*\{([^}]*)\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)/;
|
|
140
|
+
const cjsMultiMatch = cjsMultiRequire.exec(content);
|
|
141
|
+
if (cjsMultiMatch) {
|
|
142
|
+
const specifiers = cjsMultiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "withGlasstraceConfig");
|
|
143
|
+
if (specifiers.length === 0) {
|
|
144
|
+
return content.replace(
|
|
145
|
+
/const\s*\{[^}]*\}\s*=\s*require\s*\(\s*["']@glasstrace\/sdk["']\s*\)\s*;?\s*\n?/,
|
|
146
|
+
""
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
const newRequire = `const { ${specifiers.join(", ")} } = require("@glasstrace/sdk")`;
|
|
150
|
+
return content.replace(cjsMultiMatch[0], newRequire);
|
|
151
|
+
}
|
|
152
|
+
return content;
|
|
153
|
+
}
|
|
154
|
+
function cleanLeadingBlankLines(content) {
|
|
155
|
+
return content.replace(/^\n{2,}/, "\n");
|
|
156
|
+
}
|
|
157
|
+
function isInitCreatedInstrumentation(content) {
|
|
158
|
+
const lines = content.split("\n");
|
|
159
|
+
const importLines = lines.filter(
|
|
160
|
+
(l) => /^\s*import\s/.test(l) && !l.trim().startsWith("//")
|
|
161
|
+
);
|
|
162
|
+
const nonGlasstraceImports = importLines.filter(
|
|
163
|
+
(l) => !l.includes("@glasstrace/sdk")
|
|
164
|
+
);
|
|
165
|
+
if (nonGlasstraceImports.length > 0) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
const registerFnRegex = /export\s+(?:async\s+)?function\s+register\s*\([^)]*\)\s*\{/;
|
|
169
|
+
const match = registerFnRegex.exec(content);
|
|
170
|
+
if (!match) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
const afterBrace = content.slice(match.index + match[0].length);
|
|
174
|
+
const closingBraceIdx = findMatchingBrace(content, match.index + match[0].length - 1);
|
|
175
|
+
if (closingBraceIdx === -1) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
const body = afterBrace.slice(0, closingBraceIdx - (match.index + match[0].length));
|
|
179
|
+
const bodyLines = body.split("\n");
|
|
180
|
+
const statements = bodyLines.filter((l) => {
|
|
181
|
+
const trimmed = l.trim();
|
|
182
|
+
return trimmed !== "" && !trimmed.startsWith("//");
|
|
183
|
+
});
|
|
184
|
+
if (statements.length !== 1) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
if (!/^\s*registerGlasstrace\s*\(\s*\)\s*;?\s*$/.test(statements[0])) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
const beforeFn = content.slice(0, match.index);
|
|
191
|
+
const afterFn = content.slice(closingBraceIdx + 1);
|
|
192
|
+
const topLevelBefore = beforeFn.split("\n").filter((l) => {
|
|
193
|
+
const trimmed = l.trim();
|
|
194
|
+
return trimmed !== "" && !trimmed.startsWith("//") && !trimmed.startsWith("import ") && !trimmed.startsWith("import{");
|
|
195
|
+
});
|
|
196
|
+
const topLevelAfter = afterFn.split("\n").filter((l) => {
|
|
197
|
+
const trimmed = l.trim();
|
|
198
|
+
return trimmed !== "" && !trimmed.startsWith("//");
|
|
199
|
+
});
|
|
200
|
+
return topLevelBefore.length === 0 && topLevelAfter.length === 0;
|
|
201
|
+
}
|
|
202
|
+
function findMatchingBrace(text, openPos) {
|
|
203
|
+
let depth = 0;
|
|
204
|
+
for (let i = openPos; i < text.length; i++) {
|
|
205
|
+
if (text[i] === "{") {
|
|
206
|
+
depth++;
|
|
207
|
+
} else if (text[i] === "}") {
|
|
208
|
+
depth--;
|
|
209
|
+
if (depth === 0) {
|
|
210
|
+
return i;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return -1;
|
|
215
|
+
}
|
|
216
|
+
function removeRegisterGlasstrace(content) {
|
|
217
|
+
let result = content;
|
|
218
|
+
result = result.replace(
|
|
219
|
+
/[ \t]*\/\/\s*Glasstrace must be registered[^\n]*\n(?:[ \t]*\/\/[^\n]*\n)*[ \t]*registerGlasstrace\s*\(\s*\)\s*;?\s*\n?/g,
|
|
220
|
+
""
|
|
221
|
+
);
|
|
222
|
+
result = result.replace(
|
|
223
|
+
/[ \t]*registerGlasstrace\s*\(\s*\)\s*;?\s*\n?/g,
|
|
224
|
+
""
|
|
225
|
+
);
|
|
226
|
+
const soleImportPattern = /import\s*\{\s*registerGlasstrace\s*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/;
|
|
227
|
+
if (soleImportPattern.test(result)) {
|
|
228
|
+
result = result.replace(soleImportPattern, "");
|
|
229
|
+
} else {
|
|
230
|
+
const multiImportPattern = /import\s*\{([^}]*)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
231
|
+
const multiMatch = multiImportPattern.exec(result);
|
|
232
|
+
if (multiMatch) {
|
|
233
|
+
const specifiers = multiMatch[1].split(",").map((s) => s.trim()).filter((s) => s !== "" && s !== "registerGlasstrace");
|
|
234
|
+
if (specifiers.length === 0) {
|
|
235
|
+
result = result.replace(
|
|
236
|
+
/import\s*\{[^}]*\}\s*from\s*["']@glasstrace\/sdk["']\s*;?\s*\n?/,
|
|
237
|
+
""
|
|
238
|
+
);
|
|
239
|
+
} else {
|
|
240
|
+
const newImport = `import { ${specifiers.join(", ")} } from "@glasstrace/sdk"`;
|
|
241
|
+
result = result.replace(multiMatch[0], newImport);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return cleanLeadingBlankLines(result);
|
|
246
|
+
}
|
|
247
|
+
function removeMarkerSection(content) {
|
|
248
|
+
const lines = content.split("\n");
|
|
249
|
+
let startIdx = -1;
|
|
250
|
+
let endIdx = -1;
|
|
251
|
+
for (let i = 0; i < lines.length; i++) {
|
|
252
|
+
const trimmed = lines[i].trim();
|
|
253
|
+
if (trimmed === "<!-- glasstrace:mcp:start -->" || trimmed === "# glasstrace:mcp:start") {
|
|
254
|
+
startIdx = i;
|
|
255
|
+
} else if ((trimmed === "<!-- glasstrace:mcp:end -->" || trimmed === "# glasstrace:mcp:end") && startIdx !== -1) {
|
|
256
|
+
endIdx = i;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
261
|
+
return { content, removed: false };
|
|
262
|
+
}
|
|
263
|
+
const before = lines.slice(0, startIdx);
|
|
264
|
+
const after = lines.slice(endIdx + 1);
|
|
265
|
+
while (before.length > 0 && before[before.length - 1].trim() === "") {
|
|
266
|
+
before.pop();
|
|
267
|
+
}
|
|
268
|
+
const result = [...before, ...after].join("\n");
|
|
269
|
+
const trimmedResult = result.trimEnd();
|
|
270
|
+
return {
|
|
271
|
+
content: trimmedResult.length > 0 ? trimmedResult + "\n" : "",
|
|
272
|
+
removed: true
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function processJsonMcpConfig(content) {
|
|
276
|
+
let parsed;
|
|
277
|
+
try {
|
|
278
|
+
parsed = JSON.parse(content);
|
|
279
|
+
} catch {
|
|
280
|
+
return { action: "skipped" };
|
|
281
|
+
}
|
|
282
|
+
const mcpServers = parsed["mcpServers"];
|
|
283
|
+
if (!mcpServers || typeof mcpServers !== "object" || !("glasstrace" in mcpServers)) {
|
|
284
|
+
return { action: "skipped" };
|
|
285
|
+
}
|
|
286
|
+
const remainingServers = Object.keys(mcpServers).filter((k) => k !== "glasstrace");
|
|
287
|
+
const otherTopLevelKeys = Object.keys(parsed).filter((k) => k !== "mcpServers");
|
|
288
|
+
if (remainingServers.length === 0 && otherTopLevelKeys.length === 0) {
|
|
289
|
+
return { action: "deleted" };
|
|
290
|
+
}
|
|
291
|
+
const { glasstrace: _, ...rest } = mcpServers;
|
|
292
|
+
void _;
|
|
293
|
+
if (remainingServers.length > 0) {
|
|
294
|
+
parsed["mcpServers"] = rest;
|
|
295
|
+
} else {
|
|
296
|
+
delete parsed["mcpServers"];
|
|
297
|
+
}
|
|
298
|
+
return { action: "removed-key", content: JSON.stringify(parsed, null, 2) + "\n" };
|
|
299
|
+
}
|
|
300
|
+
function processTomlMcpConfig(content) {
|
|
301
|
+
if (!content.includes("[mcp_servers.glasstrace]")) {
|
|
302
|
+
return { action: "skipped" };
|
|
303
|
+
}
|
|
304
|
+
const lines = content.split("\n");
|
|
305
|
+
const startIdx = lines.findIndex(
|
|
306
|
+
(l) => l.trim() === "[mcp_servers.glasstrace]"
|
|
307
|
+
);
|
|
308
|
+
if (startIdx === -1) {
|
|
309
|
+
return { action: "skipped" };
|
|
310
|
+
}
|
|
311
|
+
let endIdx = lines.length;
|
|
312
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
313
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
314
|
+
endIdx = i;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const before = lines.slice(0, startIdx);
|
|
319
|
+
const after = lines.slice(endIdx);
|
|
320
|
+
while (before.length > 0 && before[before.length - 1].trim() === "") {
|
|
321
|
+
before.pop();
|
|
322
|
+
}
|
|
323
|
+
const result = [...before, ...after].join("\n").trimEnd();
|
|
324
|
+
if (result.trim().length === 0) {
|
|
325
|
+
return { action: "deleted" };
|
|
326
|
+
}
|
|
327
|
+
return { action: "removed-section", content: result + "\n" };
|
|
328
|
+
}
|
|
329
|
+
async function runUninit(options) {
|
|
330
|
+
const { projectRoot, dryRun } = options;
|
|
331
|
+
const summary = [];
|
|
332
|
+
const warnings = [];
|
|
333
|
+
const errors = [];
|
|
334
|
+
const prefix = dryRun ? "[dry run] " : "";
|
|
335
|
+
try {
|
|
336
|
+
let configHandled = false;
|
|
337
|
+
for (const name of NEXT_CONFIG_NAMES) {
|
|
338
|
+
const configPath = path.join(projectRoot, name);
|
|
339
|
+
if (!fs.existsSync(configPath)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
343
|
+
if (!content.includes("withGlasstraceConfig")) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const isESM = name.endsWith(".ts") || name.endsWith(".mjs");
|
|
347
|
+
const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
|
|
348
|
+
if (unwrapResult.unwrapped) {
|
|
349
|
+
const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
|
|
350
|
+
const final = cleanLeadingBlankLines(cleaned);
|
|
351
|
+
if (!dryRun) {
|
|
352
|
+
fs.writeFileSync(configPath, final, "utf-8");
|
|
353
|
+
}
|
|
354
|
+
summary.push(`${prefix}Unwrapped withGlasstraceConfig from ${name}`);
|
|
355
|
+
configHandled = true;
|
|
356
|
+
break;
|
|
357
|
+
} else {
|
|
358
|
+
warnings.push(
|
|
359
|
+
`${name} contains withGlasstraceConfig but could not be automatically unwrapped. Please remove withGlasstraceConfig() manually.`
|
|
360
|
+
);
|
|
361
|
+
configHandled = true;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (!configHandled) {
|
|
366
|
+
}
|
|
367
|
+
} catch (err) {
|
|
368
|
+
errors.push(
|
|
369
|
+
`Failed to process next.config: ${err instanceof Error ? err.message : String(err)}`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
const instrPath = path.join(projectRoot, "instrumentation.ts");
|
|
374
|
+
if (fs.existsSync(instrPath)) {
|
|
375
|
+
const content = fs.readFileSync(instrPath, "utf-8");
|
|
376
|
+
if (content.includes("registerGlasstrace") || content.includes("@glasstrace/sdk")) {
|
|
377
|
+
if (isInitCreatedInstrumentation(content)) {
|
|
378
|
+
if (!dryRun) {
|
|
379
|
+
fs.unlinkSync(instrPath);
|
|
380
|
+
}
|
|
381
|
+
summary.push(`${prefix}Deleted instrumentation.ts (init-created)`);
|
|
382
|
+
} else {
|
|
383
|
+
const cleaned = removeRegisterGlasstrace(content);
|
|
384
|
+
if (cleaned !== content) {
|
|
385
|
+
if (!dryRun) {
|
|
386
|
+
fs.writeFileSync(instrPath, cleaned, "utf-8");
|
|
387
|
+
}
|
|
388
|
+
summary.push(
|
|
389
|
+
`${prefix}Removed registerGlasstrace() from instrumentation.ts`
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
} catch (err) {
|
|
396
|
+
errors.push(
|
|
397
|
+
`Failed to process instrumentation.ts: ${err instanceof Error ? err.message : String(err)}`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
try {
|
|
401
|
+
const glasstraceDir = path.join(projectRoot, ".glasstrace");
|
|
402
|
+
if (fs.existsSync(glasstraceDir)) {
|
|
403
|
+
if (!dryRun) {
|
|
404
|
+
fs.rmSync(glasstraceDir, { recursive: true, force: true });
|
|
405
|
+
}
|
|
406
|
+
summary.push(`${prefix}Removed .glasstrace/ directory`);
|
|
407
|
+
}
|
|
408
|
+
} catch (err) {
|
|
409
|
+
errors.push(
|
|
410
|
+
`Failed to remove .glasstrace/: ${err instanceof Error ? err.message : String(err)}`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
const envPath = path.join(projectRoot, ".env.local");
|
|
415
|
+
if (fs.existsSync(envPath)) {
|
|
416
|
+
const content = fs.readFileSync(envPath, "utf-8");
|
|
417
|
+
const lines = content.split("\n");
|
|
418
|
+
const filtered = lines.filter((line) => {
|
|
419
|
+
const trimmed = line.trim();
|
|
420
|
+
return !(/^\s*#?\s*GLASSTRACE_API_KEY\s*=/.test(trimmed) || /^\s*#?\s*GLASSTRACE_COVERAGE_MAP\s*=/.test(trimmed));
|
|
421
|
+
});
|
|
422
|
+
if (filtered.length !== lines.length) {
|
|
423
|
+
const result = filtered.join("\n");
|
|
424
|
+
if (result.trim().length === 0) {
|
|
425
|
+
if (!dryRun) {
|
|
426
|
+
fs.unlinkSync(envPath);
|
|
427
|
+
}
|
|
428
|
+
summary.push(`${prefix}Deleted .env.local (no remaining entries)`);
|
|
429
|
+
} else {
|
|
430
|
+
if (!dryRun) {
|
|
431
|
+
fs.writeFileSync(envPath, result, "utf-8");
|
|
432
|
+
}
|
|
433
|
+
summary.push(`${prefix}Removed GLASSTRACE entries from .env.local`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
} catch (err) {
|
|
438
|
+
errors.push(
|
|
439
|
+
`Failed to process .env.local: ${err instanceof Error ? err.message : String(err)}`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
444
|
+
if (fs.existsSync(gitignorePath)) {
|
|
445
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
446
|
+
const lines = content.split("\n");
|
|
447
|
+
const mcpGitignoreEntries = /* @__PURE__ */ new Set([
|
|
448
|
+
".glasstrace/",
|
|
449
|
+
".mcp.json",
|
|
450
|
+
".cursor/mcp.json",
|
|
451
|
+
".gemini/settings.json",
|
|
452
|
+
".codex/config.toml"
|
|
453
|
+
]);
|
|
454
|
+
const filtered = lines.filter(
|
|
455
|
+
(line) => !mcpGitignoreEntries.has(line.trim())
|
|
456
|
+
);
|
|
457
|
+
if (filtered.length !== lines.length) {
|
|
458
|
+
const result = filtered.join("\n");
|
|
459
|
+
if (result.trim().length === 0) {
|
|
460
|
+
if (!dryRun) {
|
|
461
|
+
fs.unlinkSync(gitignorePath);
|
|
462
|
+
}
|
|
463
|
+
summary.push(`${prefix}Deleted .gitignore (no remaining entries)`);
|
|
464
|
+
} else {
|
|
465
|
+
if (!dryRun) {
|
|
466
|
+
fs.writeFileSync(gitignorePath, result, "utf-8");
|
|
467
|
+
}
|
|
468
|
+
summary.push(`${prefix}Removed Glasstrace entries from .gitignore`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
} catch (err) {
|
|
473
|
+
errors.push(
|
|
474
|
+
`Failed to process .gitignore: ${err instanceof Error ? err.message : String(err)}`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
for (const configFile of MCP_CONFIG_FILES) {
|
|
479
|
+
const configPath = path.join(projectRoot, configFile);
|
|
480
|
+
if (!fs.existsSync(configPath)) {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
484
|
+
const result = processJsonMcpConfig(content);
|
|
485
|
+
if (result.action === "deleted") {
|
|
486
|
+
if (!dryRun) {
|
|
487
|
+
fs.unlinkSync(configPath);
|
|
488
|
+
}
|
|
489
|
+
summary.push(`${prefix}Deleted ${configFile}`);
|
|
490
|
+
} else if (result.action === "removed-key" && result.content !== void 0) {
|
|
491
|
+
if (!dryRun) {
|
|
492
|
+
fs.writeFileSync(configPath, result.content, "utf-8");
|
|
493
|
+
}
|
|
494
|
+
summary.push(`${prefix}Removed glasstrace from ${configFile}`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const codexConfigPath = path.join(projectRoot, ".codex", "config.toml");
|
|
498
|
+
if (fs.existsSync(codexConfigPath)) {
|
|
499
|
+
const content = fs.readFileSync(codexConfigPath, "utf-8");
|
|
500
|
+
const tomlResult = processTomlMcpConfig(content);
|
|
501
|
+
if (tomlResult.action === "deleted") {
|
|
502
|
+
if (!dryRun) {
|
|
503
|
+
fs.unlinkSync(codexConfigPath);
|
|
504
|
+
}
|
|
505
|
+
summary.push(`${prefix}Deleted .codex/config.toml`);
|
|
506
|
+
} else if (tomlResult.action === "removed-section" && tomlResult.content !== void 0) {
|
|
507
|
+
if (!dryRun) {
|
|
508
|
+
fs.writeFileSync(codexConfigPath, tomlResult.content, "utf-8");
|
|
509
|
+
}
|
|
510
|
+
summary.push(`${prefix}Removed glasstrace from .codex/config.toml`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
const hasWindsurfMarkers = fs.existsSync(path.join(projectRoot, ".windsurfrules")) || fs.existsSync(path.join(projectRoot, ".windsurf"));
|
|
514
|
+
if (hasWindsurfMarkers) {
|
|
515
|
+
const windsurfConfigPath = path.join(
|
|
516
|
+
os.homedir(),
|
|
517
|
+
".codeium",
|
|
518
|
+
"windsurf",
|
|
519
|
+
"mcp_config.json"
|
|
520
|
+
);
|
|
521
|
+
if (fs.existsSync(windsurfConfigPath)) {
|
|
522
|
+
const content = fs.readFileSync(windsurfConfigPath, "utf-8");
|
|
523
|
+
const windsurfResult = processJsonMcpConfig(content);
|
|
524
|
+
if (windsurfResult.action === "deleted") {
|
|
525
|
+
if (!dryRun) {
|
|
526
|
+
fs.unlinkSync(windsurfConfigPath);
|
|
527
|
+
}
|
|
528
|
+
summary.push(`${prefix}Deleted Windsurf MCP config`);
|
|
529
|
+
} else if (windsurfResult.action === "removed-key" && windsurfResult.content !== void 0) {
|
|
530
|
+
if (!dryRun) {
|
|
531
|
+
fs.writeFileSync(windsurfConfigPath, windsurfResult.content, "utf-8");
|
|
532
|
+
}
|
|
533
|
+
summary.push(`${prefix}Removed glasstrace from Windsurf MCP config`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
} catch (err) {
|
|
538
|
+
errors.push(
|
|
539
|
+
`Failed to process MCP config: ${err instanceof Error ? err.message : String(err)}`
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
for (const infoFile of AGENT_INFO_FILES) {
|
|
544
|
+
const filePath = path.join(projectRoot, infoFile);
|
|
545
|
+
if (!fs.existsSync(filePath)) {
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
549
|
+
const result = removeMarkerSection(content);
|
|
550
|
+
if (result.removed) {
|
|
551
|
+
if (result.content.trim().length === 0) {
|
|
552
|
+
if (!dryRun) {
|
|
553
|
+
fs.unlinkSync(filePath);
|
|
554
|
+
}
|
|
555
|
+
summary.push(`${prefix}Deleted ${infoFile} (only contained Glasstrace section)`);
|
|
556
|
+
} else {
|
|
557
|
+
if (!dryRun) {
|
|
558
|
+
fs.writeFileSync(filePath, result.content, "utf-8");
|
|
559
|
+
}
|
|
560
|
+
summary.push(`${prefix}Removed Glasstrace section from ${infoFile}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
} catch (err) {
|
|
565
|
+
errors.push(
|
|
566
|
+
`Failed to process agent info files: ${err instanceof Error ? err.message : String(err)}`
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
if (summary.length === 0 && errors.length === 0) {
|
|
570
|
+
summary.push("No Glasstrace artifacts found \u2014 nothing to do.");
|
|
571
|
+
}
|
|
572
|
+
return { exitCode: errors.length > 0 ? 1 : 0, summary, warnings, errors };
|
|
573
|
+
}
|
|
574
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
575
|
+
0 && (module.exports = {
|
|
576
|
+
findMatchingParen,
|
|
577
|
+
isInitCreatedInstrumentation,
|
|
578
|
+
processJsonMcpConfig,
|
|
579
|
+
processTomlMcpConfig,
|
|
580
|
+
removeGlasstraceConfigImport,
|
|
581
|
+
removeMarkerSection,
|
|
582
|
+
removeRegisterGlasstrace,
|
|
583
|
+
runUninit,
|
|
584
|
+
unwrapCJSExport,
|
|
585
|
+
unwrapExport
|
|
586
|
+
});
|
|
587
|
+
//# sourceMappingURL=uninit.cjs.map
|