@glasstrace/sdk 0.15.1 → 0.16.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/README.md +84 -1
- package/dist/adapters/drizzle.js +2 -5
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/{chunk-PD2SKFQQ.js → chunk-55FBXXER.js} +4 -8
- package/dist/{chunk-PD2SKFQQ.js.map → chunk-55FBXXER.js.map} +1 -1
- package/dist/chunk-5C2TJFLB.js +851 -0
- package/dist/chunk-5C2TJFLB.js.map +1 -0
- package/dist/{chunk-YMEXDDTA.js → chunk-7JBKXSBU.js} +3 -99
- package/dist/chunk-7JBKXSBU.js.map +1 -0
- package/dist/{chunk-2LDBR3F3.js → chunk-BANTDXUT.js} +15 -74
- package/dist/chunk-BANTDXUT.js.map +1 -0
- package/dist/{chunk-ZNOD6FC7.js → chunk-CTJI2YKA.js} +8 -15
- package/dist/{chunk-ZNOD6FC7.js.map → chunk-CTJI2YKA.js.map} +1 -1
- package/dist/{chunk-WK7MPK2T.js → chunk-DQ25VOKK.js} +1 -89
- package/dist/chunk-DQ25VOKK.js.map +1 -0
- package/dist/{chunk-BL3YDC6V.js → chunk-DXRZKKSO.js} +1 -6
- package/dist/{chunk-BL3YDC6V.js.map → chunk-DXRZKKSO.js.map} +1 -1
- package/dist/{chunk-BGZ7J74D.js → chunk-NSBPE2FW.js} +2 -16
- package/dist/{chunk-A2AZL6MZ.js → chunk-O63DJKIJ.js} +169 -18
- package/dist/chunk-O63DJKIJ.js.map +1 -0
- package/dist/{chunk-ECEN724Y.js → chunk-TM5NKZTO.js} +4 -8
- package/dist/{chunk-ECEN724Y.js.map → chunk-TM5NKZTO.js.map} +1 -1
- package/dist/chunk-VUZCLMIX.js +57 -0
- package/dist/chunk-VUZCLMIX.js.map +1 -0
- package/dist/{chunk-OSXIUKD5.js → chunk-WZXVS2EO.js} +1 -6
- package/dist/{chunk-OSXIUKD5.js.map → chunk-WZXVS2EO.js.map} +1 -1
- package/dist/{chunk-ROFOJQWN.js → chunk-XNDHQN4S.js} +7 -11
- package/dist/{chunk-ROFOJQWN.js.map → chunk-XNDHQN4S.js.map} +1 -1
- package/dist/cli/init.cjs +673 -161
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +54 -1
- package/dist/cli/init.d.ts +54 -1
- package/dist/cli/init.js +146 -37
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +16 -16
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +10 -13
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/status.cjs +2 -2
- package/dist/cli/status.js +4 -7
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/uninit.cjs +56 -59
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.js +4 -4
- package/dist/cli/validate.cjs +2 -2
- package/dist/cli/validate.js +3 -6
- package/dist/cli/validate.js.map +1 -1
- package/dist/{esm-MDK7CZID.js → esm-KBPHCVB4.js} +3 -3
- package/dist/{getMachineId-bsd-4NIRBWME.js → getMachineId-bsd-345PYXFX.js} +4 -7
- package/dist/{getMachineId-bsd-4NIRBWME.js.map → getMachineId-bsd-345PYXFX.js.map} +1 -1
- package/dist/{getMachineId-darwin-2XNOCCJQ.js → getMachineId-darwin-5L2D25AD.js} +4 -7
- package/dist/{getMachineId-darwin-2XNOCCJQ.js.map → getMachineId-darwin-5L2D25AD.js.map} +1 -1
- package/dist/{getMachineId-linux-V6YSQEY7.js → getMachineId-linux-KJR4P5HN.js} +3 -6
- package/dist/{getMachineId-linux-V6YSQEY7.js.map → getMachineId-linux-KJR4P5HN.js.map} +1 -1
- package/dist/{getMachineId-unsupported-4FKBJNVO.js → getMachineId-unsupported-NDNXDYDY.js} +3 -6
- package/dist/{getMachineId-unsupported-4FKBJNVO.js.map → getMachineId-unsupported-NDNXDYDY.js.map} +1 -1
- package/dist/{getMachineId-win-WLRZBKVG.js → getMachineId-win-T7PJNJXG.js} +4 -7
- package/dist/{getMachineId-win-WLRZBKVG.js.map → getMachineId-win-T7PJNJXG.js.map} +1 -1
- package/dist/index.cjs +449 -461
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +195 -701
- package/dist/index.js.map +1 -1
- package/dist/{monorepo-YILKGQXQ.js → monorepo-N5Z63XP7.js} +4 -4
- package/dist/{source-map-uploader-3GWUQDTS.js → source-map-uploader-MUZPI2S5.js} +5 -4
- package/dist/source-map-uploader-MUZPI2S5.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2LDBR3F3.js.map +0 -1
- package/dist/chunk-A2AZL6MZ.js.map +0 -1
- package/dist/chunk-BGZ7J74D.js.map +0 -1
- package/dist/chunk-UPS5BGER.js +0 -182
- package/dist/chunk-UPS5BGER.js.map +0 -1
- package/dist/chunk-WK7MPK2T.js.map +0 -1
- package/dist/chunk-YMEXDDTA.js.map +0 -1
- /package/dist/{esm-MDK7CZID.js.map → chunk-NSBPE2FW.js.map} +0 -0
- /package/dist/{monorepo-YILKGQXQ.js.map → esm-KBPHCVB4.js.map} +0 -0
- /package/dist/{source-map-uploader-3GWUQDTS.js.map → monorepo-N5Z63XP7.js.map} +0 -0
package/dist/cli/mcp-add.js
CHANGED
|
@@ -5,28 +5,25 @@ import {
|
|
|
5
5
|
injectInfoSection,
|
|
6
6
|
updateGitignore,
|
|
7
7
|
writeMcpConfig
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-CTJI2YKA.js";
|
|
9
9
|
import {
|
|
10
10
|
readAnonKey
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-TM5NKZTO.js";
|
|
12
|
+
import "../chunk-7JBKXSBU.js";
|
|
13
13
|
import {
|
|
14
14
|
scaffoldMcpMarker
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-O63DJKIJ.js";
|
|
16
16
|
import {
|
|
17
17
|
MCP_ENDPOINT,
|
|
18
18
|
formatAgentName
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import
|
|
21
|
-
init_esm_shims
|
|
22
|
-
} from "../chunk-BGZ7J74D.js";
|
|
19
|
+
} from "../chunk-DXRZKKSO.js";
|
|
20
|
+
import "../chunk-NSBPE2FW.js";
|
|
23
21
|
|
|
24
22
|
// src/cli/mcp-add.ts
|
|
25
|
-
|
|
26
|
-
import
|
|
27
|
-
import * as
|
|
28
|
-
import
|
|
29
|
-
import { promisify } from "util";
|
|
23
|
+
import { execFile as execFileCb } from "node:child_process";
|
|
24
|
+
import * as fs from "node:fs";
|
|
25
|
+
import * as path from "node:path";
|
|
26
|
+
import { promisify } from "node:util";
|
|
30
27
|
var execFileAsync = promisify(execFileCb);
|
|
31
28
|
async function registerViaCli(agent, anonKey) {
|
|
32
29
|
if (!agent.cliAvailable) {
|
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":"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","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":[]}
|
package/dist/cli/status.cjs
CHANGED
|
@@ -33,8 +33,8 @@ __export(status_exports, {
|
|
|
33
33
|
runStatus: () => runStatus
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(status_exports);
|
|
36
|
-
var fs = __toESM(require("fs"), 1);
|
|
37
|
-
var path = __toESM(require("path"), 1);
|
|
36
|
+
var fs = __toESM(require("node:fs"), 1);
|
|
37
|
+
var path = __toESM(require("node:path"), 1);
|
|
38
38
|
|
|
39
39
|
// src/cli/constants.ts
|
|
40
40
|
var NEXT_CONFIG_NAMES = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
package/dist/cli/status.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NEXT_CONFIG_NAMES
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import
|
|
5
|
-
init_esm_shims
|
|
6
|
-
} from "../chunk-BGZ7J74D.js";
|
|
3
|
+
} from "../chunk-DXRZKKSO.js";
|
|
4
|
+
import "../chunk-NSBPE2FW.js";
|
|
7
5
|
|
|
8
6
|
// src/cli/status.ts
|
|
9
|
-
|
|
10
|
-
import * as
|
|
11
|
-
import * as path from "path";
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as path from "node:path";
|
|
12
9
|
var MCP_JSON_FILES = [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json", ".glasstrace/mcp.json"];
|
|
13
10
|
var MCP_TOML_FILES = [".codex/config.toml"];
|
|
14
11
|
var AGENT_INFO_FILES = [
|
package/dist/cli/status.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/status.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { NEXT_CONFIG_NAMES } from \"./constants.js\";\n\n/**\n * JSON-based MCP config files that init may create.\n * Includes .glasstrace/mcp.json (CI/generic fallback) in addition to the\n * agent-specific files that uninit.ts handles.\n */\nconst MCP_JSON_FILES = [\".mcp.json\", \".cursor/mcp.json\", \".gemini/settings.json\", \".glasstrace/mcp.json\"] as const;\n\n/**\n * TOML-based MCP config files (Codex uses this format).\n */\nconst MCP_TOML_FILES = [\".codex/config.toml\"] as const;\n\n/**\n * Agent info files that may contain glasstrace marker sections.\n */\nconst AGENT_INFO_FILES = [\n \"CLAUDE.md\",\n \"codex.md\",\n \".cursorrules\",\n] as const;\n\n/**\n * Instrumentation file names in priority order.\n */\nconst INSTRUMENTATION_FILES = [\n \"instrumentation.ts\",\n \"instrumentation.js\",\n \"instrumentation.mjs\",\n \"src/instrumentation.ts\",\n \"src/instrumentation.js\",\n \"src/instrumentation.mjs\",\n] as const;\n\n/**\n * Machine-readable SDK configuration state.\n * This interface is the public contract for AI agents — fields may be added\n * but never removed or renamed without a major version bump.\n */\n/** Runtime state snapshot read from .glasstrace/runtime-state.json. */\nexport interface RuntimeStateSnapshot {\n /** Whether the runtime state file exists and was readable. */\n available: boolean;\n /** Whether the process that wrote the state is likely still running. */\n stale: boolean;\n /** Core lifecycle state (e.g., \"ACTIVE\", \"KEY_PENDING\", \"SHUTDOWN\"). */\n coreState: string | null;\n /** Auth lifecycle state (e.g., \"ANONYMOUS\", \"AUTHENTICATED\"). */\n authState: string | null;\n /** OTel coexistence state (e.g., \"OWNS_PROVIDER\", \"AUTO_ATTACHED\"). */\n otelState: string | null;\n /** OTel scenario (e.g., \"A\", \"B-auto\"). */\n otelScenario: string | null;\n /** When the state was last written. */\n updatedAt: string | null;\n /** PID of the process that wrote the state. */\n pid: number | null;\n}\n\nexport interface StatusResult {\n /** Whether @glasstrace/sdk is in package.json dependencies or devDependencies. */\n installed: boolean;\n /** Whether the .glasstrace/ directory exists. */\n initialized: boolean;\n /** Whether an instrumentation file exists with registerGlasstrace(). */\n instrumentation: boolean;\n /** Whether next.config is wrapped with withGlasstraceConfig(). */\n configWrapped: boolean;\n /** Whether .glasstrace/anon_key exists. */\n anonKey: boolean;\n /** Whether any MCP config file has a glasstrace server entry. */\n mcpConfigured: boolean;\n /** Which agent info files have glasstrace marker sections. */\n agents: string[];\n /** Runtime state from the running SDK process (if available). */\n runtime: RuntimeStateSnapshot;\n}\n\n/**\n * Options for the status command.\n */\nexport interface StatusOptions {\n projectRoot: string;\n}\n\n/**\n * Checks SDK configuration state by reading filesystem markers.\n * This function is read-only — it never modifies files or creates directories.\n */\nexport function runStatus(options: StatusOptions): StatusResult {\n const root = options.projectRoot;\n\n return {\n installed: checkInstalled(root),\n initialized: checkInitialized(root),\n instrumentation: checkInstrumentation(root),\n configWrapped: checkConfigWrapped(root),\n anonKey: checkAnonKey(root),\n mcpConfigured: checkMcpConfigured(root),\n agents: checkAgents(root),\n runtime: readRuntimeState(root),\n };\n}\n\nfunction checkInstalled(root: string): boolean {\n try {\n const pkgPath = path.join(root, \"package.json\");\n const content = fs.readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n const deps = pkg[\"dependencies\"] as Record<string, unknown> | undefined;\n const devDeps = pkg[\"devDependencies\"] as Record<string, unknown> | undefined;\n return (\n (deps != null && \"@glasstrace/sdk\" in deps) ||\n (devDeps != null && \"@glasstrace/sdk\" in devDeps)\n );\n } catch {\n return false;\n }\n}\n\nfunction checkInitialized(root: string): boolean {\n try {\n return fs.statSync(path.join(root, \".glasstrace\")).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction checkInstrumentation(root: string): boolean {\n for (const name of INSTRUMENTATION_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n if (content.includes(\"registerGlasstrace\")) {\n return true;\n }\n } catch {\n // File doesn't exist or is unreadable — try next\n }\n }\n return false;\n}\n\nfunction checkConfigWrapped(root: string): boolean {\n for (const name of NEXT_CONFIG_NAMES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n if (content.includes(\"withGlasstraceConfig\")) {\n return true;\n }\n } catch {\n // File doesn't exist or is unreadable — try next\n }\n }\n return false;\n}\n\nfunction checkAnonKey(root: string): boolean {\n try {\n return fs.statSync(path.join(root, \".glasstrace\", \"anon_key\")).isFile();\n } catch {\n return false;\n }\n}\n\nfunction checkMcpConfigured(root: string): boolean {\n // Check JSON-based MCP config files\n for (const name of MCP_JSON_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n const parsed = JSON.parse(content) as Record<string, unknown>;\n const mcpServers = parsed[\"mcpServers\"] as Record<string, unknown> | undefined;\n if (mcpServers && typeof mcpServers === \"object\" && \"glasstrace\" in mcpServers) {\n return true;\n }\n } catch {\n // File doesn't exist, is unreadable, or has invalid JSON — try next\n }\n }\n\n // Check TOML-based MCP config files (Codex)\n for (const name of MCP_TOML_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n if (content.includes(\"[mcp_servers.glasstrace]\")) {\n return true;\n }\n } catch {\n // File doesn't exist or is unreadable — try next\n }\n }\n\n return false;\n}\n\nfunction checkAgents(root: string): string[] {\n const found: string[] = [];\n for (const name of AGENT_INFO_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n const hasHtmlMarkers =\n content.includes(\"<!-- glasstrace:mcp:start -->\") &&\n content.includes(\"<!-- glasstrace:mcp:end -->\");\n const hasHashMarkers =\n content.includes(\"# glasstrace:mcp:start\") &&\n content.includes(\"# glasstrace:mcp:end\");\n if (hasHtmlMarkers || hasHashMarkers) {\n found.push(name);\n }\n } catch {\n // File doesn't exist or is unreadable — skip\n }\n }\n return found;\n}\n\nconst STALE_THRESHOLD_MS = 30_000; // 30 seconds\n\nfunction readRuntimeState(root: string): RuntimeStateSnapshot {\n const empty: RuntimeStateSnapshot = {\n available: false,\n stale: false,\n coreState: null,\n authState: null,\n otelState: null,\n otelScenario: null,\n updatedAt: null,\n pid: null,\n };\n\n try {\n const filePath = path.join(root, \".glasstrace\", \"runtime-state.json\");\n const content = fs.readFileSync(filePath, \"utf-8\");\n const parsed = JSON.parse(content) as Record<string, unknown>;\n\n const updatedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : null;\n const pid = typeof parsed.pid === \"number\" ? parsed.pid : null;\n const core = parsed.core as Record<string, unknown> | undefined;\n const auth = parsed.auth as Record<string, unknown> | undefined;\n const otel = parsed.otel as Record<string, unknown> | undefined;\n\n const coreState = typeof core?.state === \"string\" ? core.state : null;\n const authState = typeof auth?.state === \"string\" ? auth.state : null;\n const otelState = typeof otel?.state === \"string\" ? otel.state : null;\n const otelScenario = typeof otel?.scenario === \"string\" ? otel.scenario : null;\n\n // Staleness detection\n let stale = false;\n if (coreState === \"SHUTDOWN\") {\n stale = false; // Clean shutdown — not stale, just finished\n } else if (updatedAt) {\n const updatedMs = new Date(updatedAt).getTime();\n const age = Number.isFinite(updatedMs) ? Date.now() - updatedMs : Infinity;\n if (age > STALE_THRESHOLD_MS) {\n // Check if the process is still running\n if (pid && pid > 0) {\n try {\n process.kill(pid, 0); // Signal 0 = existence check\n // If we get here, process exists. EPERM would also throw,\n // but with code \"EPERM\" — meaning the process exists but\n // we lack permission. Both mean \"not stale.\"\n stale = false;\n } catch (err: unknown) {\n const code = (err as { code?: string })?.code;\n if (code === \"EPERM\") {\n stale = false; // Process exists, we just can't signal it\n } else {\n stale = true; // ESRCH or other — process gone\n }\n }\n } else {\n stale = true; // No valid PID — can't verify\n }\n }\n }\n\n return {\n available: true,\n stale,\n coreState,\n authState,\n otelState,\n otelScenario,\n updatedAt,\n pid,\n };\n } catch {\n return empty;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/status.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { NEXT_CONFIG_NAMES } from \"./constants.js\";\n\n/**\n * JSON-based MCP config files that init may create.\n * Includes .glasstrace/mcp.json (CI/generic fallback) in addition to the\n * agent-specific files that uninit.ts handles.\n */\nconst MCP_JSON_FILES = [\".mcp.json\", \".cursor/mcp.json\", \".gemini/settings.json\", \".glasstrace/mcp.json\"] as const;\n\n/**\n * TOML-based MCP config files (Codex uses this format).\n */\nconst MCP_TOML_FILES = [\".codex/config.toml\"] as const;\n\n/**\n * Agent info files that may contain glasstrace marker sections.\n */\nconst AGENT_INFO_FILES = [\n \"CLAUDE.md\",\n \"codex.md\",\n \".cursorrules\",\n] as const;\n\n/**\n * Instrumentation file names in priority order.\n */\nconst INSTRUMENTATION_FILES = [\n \"instrumentation.ts\",\n \"instrumentation.js\",\n \"instrumentation.mjs\",\n \"src/instrumentation.ts\",\n \"src/instrumentation.js\",\n \"src/instrumentation.mjs\",\n] as const;\n\n/**\n * Machine-readable SDK configuration state.\n * This interface is the public contract for AI agents — fields may be added\n * but never removed or renamed without a major version bump.\n */\n/** Runtime state snapshot read from .glasstrace/runtime-state.json. */\nexport interface RuntimeStateSnapshot {\n /** Whether the runtime state file exists and was readable. */\n available: boolean;\n /** Whether the process that wrote the state is likely still running. */\n stale: boolean;\n /** Core lifecycle state (e.g., \"ACTIVE\", \"KEY_PENDING\", \"SHUTDOWN\"). */\n coreState: string | null;\n /** Auth lifecycle state (e.g., \"ANONYMOUS\", \"AUTHENTICATED\"). */\n authState: string | null;\n /** OTel coexistence state (e.g., \"OWNS_PROVIDER\", \"AUTO_ATTACHED\"). */\n otelState: string | null;\n /** OTel scenario (e.g., \"A\", \"B-auto\"). */\n otelScenario: string | null;\n /** When the state was last written. */\n updatedAt: string | null;\n /** PID of the process that wrote the state. */\n pid: number | null;\n}\n\nexport interface StatusResult {\n /** Whether @glasstrace/sdk is in package.json dependencies or devDependencies. */\n installed: boolean;\n /** Whether the .glasstrace/ directory exists. */\n initialized: boolean;\n /** Whether an instrumentation file exists with registerGlasstrace(). */\n instrumentation: boolean;\n /** Whether next.config is wrapped with withGlasstraceConfig(). */\n configWrapped: boolean;\n /** Whether .glasstrace/anon_key exists. */\n anonKey: boolean;\n /** Whether any MCP config file has a glasstrace server entry. */\n mcpConfigured: boolean;\n /** Which agent info files have glasstrace marker sections. */\n agents: string[];\n /** Runtime state from the running SDK process (if available). */\n runtime: RuntimeStateSnapshot;\n}\n\n/**\n * Options for the status command.\n */\nexport interface StatusOptions {\n projectRoot: string;\n}\n\n/**\n * Checks SDK configuration state by reading filesystem markers.\n * This function is read-only — it never modifies files or creates directories.\n */\nexport function runStatus(options: StatusOptions): StatusResult {\n const root = options.projectRoot;\n\n return {\n installed: checkInstalled(root),\n initialized: checkInitialized(root),\n instrumentation: checkInstrumentation(root),\n configWrapped: checkConfigWrapped(root),\n anonKey: checkAnonKey(root),\n mcpConfigured: checkMcpConfigured(root),\n agents: checkAgents(root),\n runtime: readRuntimeState(root),\n };\n}\n\nfunction checkInstalled(root: string): boolean {\n try {\n const pkgPath = path.join(root, \"package.json\");\n const content = fs.readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n const deps = pkg[\"dependencies\"] as Record<string, unknown> | undefined;\n const devDeps = pkg[\"devDependencies\"] as Record<string, unknown> | undefined;\n return (\n (deps != null && \"@glasstrace/sdk\" in deps) ||\n (devDeps != null && \"@glasstrace/sdk\" in devDeps)\n );\n } catch {\n return false;\n }\n}\n\nfunction checkInitialized(root: string): boolean {\n try {\n return fs.statSync(path.join(root, \".glasstrace\")).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction checkInstrumentation(root: string): boolean {\n for (const name of INSTRUMENTATION_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n if (content.includes(\"registerGlasstrace\")) {\n return true;\n }\n } catch {\n // File doesn't exist or is unreadable — try next\n }\n }\n return false;\n}\n\nfunction checkConfigWrapped(root: string): boolean {\n for (const name of NEXT_CONFIG_NAMES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n if (content.includes(\"withGlasstraceConfig\")) {\n return true;\n }\n } catch {\n // File doesn't exist or is unreadable — try next\n }\n }\n return false;\n}\n\nfunction checkAnonKey(root: string): boolean {\n try {\n return fs.statSync(path.join(root, \".glasstrace\", \"anon_key\")).isFile();\n } catch {\n return false;\n }\n}\n\nfunction checkMcpConfigured(root: string): boolean {\n // Check JSON-based MCP config files\n for (const name of MCP_JSON_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n const parsed = JSON.parse(content) as Record<string, unknown>;\n const mcpServers = parsed[\"mcpServers\"] as Record<string, unknown> | undefined;\n if (mcpServers && typeof mcpServers === \"object\" && \"glasstrace\" in mcpServers) {\n return true;\n }\n } catch {\n // File doesn't exist, is unreadable, or has invalid JSON — try next\n }\n }\n\n // Check TOML-based MCP config files (Codex)\n for (const name of MCP_TOML_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n if (content.includes(\"[mcp_servers.glasstrace]\")) {\n return true;\n }\n } catch {\n // File doesn't exist or is unreadable — try next\n }\n }\n\n return false;\n}\n\nfunction checkAgents(root: string): string[] {\n const found: string[] = [];\n for (const name of AGENT_INFO_FILES) {\n try {\n const content = fs.readFileSync(path.join(root, name), \"utf-8\");\n const hasHtmlMarkers =\n content.includes(\"<!-- glasstrace:mcp:start -->\") &&\n content.includes(\"<!-- glasstrace:mcp:end -->\");\n const hasHashMarkers =\n content.includes(\"# glasstrace:mcp:start\") &&\n content.includes(\"# glasstrace:mcp:end\");\n if (hasHtmlMarkers || hasHashMarkers) {\n found.push(name);\n }\n } catch {\n // File doesn't exist or is unreadable — skip\n }\n }\n return found;\n}\n\nconst STALE_THRESHOLD_MS = 30_000; // 30 seconds\n\nfunction readRuntimeState(root: string): RuntimeStateSnapshot {\n const empty: RuntimeStateSnapshot = {\n available: false,\n stale: false,\n coreState: null,\n authState: null,\n otelState: null,\n otelScenario: null,\n updatedAt: null,\n pid: null,\n };\n\n try {\n const filePath = path.join(root, \".glasstrace\", \"runtime-state.json\");\n const content = fs.readFileSync(filePath, \"utf-8\");\n const parsed = JSON.parse(content) as Record<string, unknown>;\n\n const updatedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : null;\n const pid = typeof parsed.pid === \"number\" ? parsed.pid : null;\n const core = parsed.core as Record<string, unknown> | undefined;\n const auth = parsed.auth as Record<string, unknown> | undefined;\n const otel = parsed.otel as Record<string, unknown> | undefined;\n\n const coreState = typeof core?.state === \"string\" ? core.state : null;\n const authState = typeof auth?.state === \"string\" ? auth.state : null;\n const otelState = typeof otel?.state === \"string\" ? otel.state : null;\n const otelScenario = typeof otel?.scenario === \"string\" ? otel.scenario : null;\n\n // Staleness detection\n let stale = false;\n if (coreState === \"SHUTDOWN\") {\n stale = false; // Clean shutdown — not stale, just finished\n } else if (updatedAt) {\n const updatedMs = new Date(updatedAt).getTime();\n const age = Number.isFinite(updatedMs) ? Date.now() - updatedMs : Infinity;\n if (age > STALE_THRESHOLD_MS) {\n // Check if the process is still running\n if (pid && pid > 0) {\n try {\n process.kill(pid, 0); // Signal 0 = existence check\n // If we get here, process exists. EPERM would also throw,\n // but with code \"EPERM\" — meaning the process exists but\n // we lack permission. Both mean \"not stale.\"\n stale = false;\n } catch (err: unknown) {\n const code = (err as { code?: string })?.code;\n if (code === \"EPERM\") {\n stale = false; // Process exists, we just can't signal it\n } else {\n stale = true; // ESRCH or other — process gone\n }\n }\n } else {\n stale = true; // No valid PID — can't verify\n }\n }\n }\n\n return {\n available: true,\n stale,\n coreState,\n authState,\n otelState,\n otelScenario,\n updatedAt,\n pid,\n };\n } catch {\n return empty;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/uninit.cjs
CHANGED
|
@@ -45,17 +45,14 @@ __export(uninit_exports, {
|
|
|
45
45
|
writeShutdownMarker: () => writeShutdownMarker
|
|
46
46
|
});
|
|
47
47
|
module.exports = __toCommonJS(uninit_exports);
|
|
48
|
-
var
|
|
49
|
-
var os = __toESM(require("os"), 1);
|
|
50
|
-
var
|
|
48
|
+
var fs = __toESM(require("node:fs"), 1);
|
|
49
|
+
var os = __toESM(require("node:os"), 1);
|
|
50
|
+
var path = __toESM(require("node:path"), 1);
|
|
51
51
|
|
|
52
52
|
// src/cli/constants.ts
|
|
53
53
|
var NEXT_CONFIG_NAMES = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
54
54
|
|
|
55
55
|
// src/cli/scaffolder.ts
|
|
56
|
-
var import_node_crypto = require("crypto");
|
|
57
|
-
var fs = __toESM(require("fs"), 1);
|
|
58
|
-
var path = __toESM(require("path"), 1);
|
|
59
56
|
function readEnvLocalApiKey(content) {
|
|
60
57
|
let last = null;
|
|
61
58
|
const regex = /^\s*GLASSTRACE_API_KEY\s*=\s*(.*)$/gm;
|
|
@@ -381,24 +378,24 @@ function processTomlMcpConfig(content) {
|
|
|
381
378
|
return { action: "removed-section", content: result + "\n" };
|
|
382
379
|
}
|
|
383
380
|
function writeShutdownMarker(projectRoot) {
|
|
384
|
-
const dirPath =
|
|
385
|
-
if (!
|
|
381
|
+
const dirPath = path.join(projectRoot, ".glasstrace");
|
|
382
|
+
if (!fs.existsSync(dirPath)) {
|
|
386
383
|
return false;
|
|
387
384
|
}
|
|
388
|
-
const markerPath =
|
|
385
|
+
const markerPath = path.join(dirPath, "shutdown-requested");
|
|
389
386
|
const tmpPath = `${markerPath}.tmp`;
|
|
390
387
|
const body = JSON.stringify({ requestedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
391
388
|
try {
|
|
392
|
-
|
|
389
|
+
fs.writeFileSync(tmpPath, body, { encoding: "utf-8", mode: 384 });
|
|
393
390
|
try {
|
|
394
|
-
|
|
391
|
+
fs.chmodSync(tmpPath, 384);
|
|
395
392
|
} catch {
|
|
396
393
|
}
|
|
397
|
-
|
|
394
|
+
fs.renameSync(tmpPath, markerPath);
|
|
398
395
|
return true;
|
|
399
396
|
} catch {
|
|
400
397
|
try {
|
|
401
|
-
|
|
398
|
+
fs.unlinkSync(tmpPath);
|
|
402
399
|
} catch {
|
|
403
400
|
}
|
|
404
401
|
return false;
|
|
@@ -406,7 +403,7 @@ function writeShutdownMarker(projectRoot) {
|
|
|
406
403
|
}
|
|
407
404
|
async function defaultPrompt(question, defaultValue) {
|
|
408
405
|
if (!process.stdin.isTTY) return defaultValue;
|
|
409
|
-
const readline = await import("readline");
|
|
406
|
+
const readline = await import("node:readline");
|
|
410
407
|
const rl = readline.createInterface({
|
|
411
408
|
input: process.stdin,
|
|
412
409
|
output: process.stdout
|
|
@@ -439,8 +436,8 @@ async function runUninit(options) {
|
|
|
439
436
|
summary.push("Wrote .glasstrace/shutdown-requested marker");
|
|
440
437
|
}
|
|
441
438
|
} else {
|
|
442
|
-
const dirPath =
|
|
443
|
-
if (
|
|
439
|
+
const dirPath = path.join(projectRoot, ".glasstrace");
|
|
440
|
+
if (fs.existsSync(dirPath)) {
|
|
444
441
|
summary.push(`${prefix}Would write .glasstrace/shutdown-requested marker`);
|
|
445
442
|
}
|
|
446
443
|
}
|
|
@@ -452,11 +449,11 @@ async function runUninit(options) {
|
|
|
452
449
|
try {
|
|
453
450
|
let configHandled = false;
|
|
454
451
|
for (const name of NEXT_CONFIG_NAMES) {
|
|
455
|
-
const configPath =
|
|
456
|
-
if (!
|
|
452
|
+
const configPath = path.join(projectRoot, name);
|
|
453
|
+
if (!fs.existsSync(configPath)) {
|
|
457
454
|
continue;
|
|
458
455
|
}
|
|
459
|
-
const content =
|
|
456
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
460
457
|
if (!content.includes("withGlasstraceConfig")) {
|
|
461
458
|
continue;
|
|
462
459
|
}
|
|
@@ -466,7 +463,7 @@ async function runUninit(options) {
|
|
|
466
463
|
const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
|
|
467
464
|
const final = cleanLeadingBlankLines(cleaned);
|
|
468
465
|
if (!dryRun) {
|
|
469
|
-
|
|
466
|
+
fs.writeFileSync(configPath, final, "utf-8");
|
|
470
467
|
}
|
|
471
468
|
summary.push(`${prefix}Unwrapped withGlasstraceConfig from ${name}`);
|
|
472
469
|
configHandled = true;
|
|
@@ -487,20 +484,20 @@ async function runUninit(options) {
|
|
|
487
484
|
);
|
|
488
485
|
}
|
|
489
486
|
try {
|
|
490
|
-
const instrPath =
|
|
491
|
-
if (
|
|
492
|
-
const content =
|
|
487
|
+
const instrPath = path.join(projectRoot, "instrumentation.ts");
|
|
488
|
+
if (fs.existsSync(instrPath)) {
|
|
489
|
+
const content = fs.readFileSync(instrPath, "utf-8");
|
|
493
490
|
if (content.includes("registerGlasstrace") || content.includes("@glasstrace/sdk")) {
|
|
494
491
|
if (isInitCreatedInstrumentation(content)) {
|
|
495
492
|
if (!dryRun) {
|
|
496
|
-
|
|
493
|
+
fs.unlinkSync(instrPath);
|
|
497
494
|
}
|
|
498
495
|
summary.push(`${prefix}Deleted instrumentation.ts (init-created)`);
|
|
499
496
|
} else {
|
|
500
497
|
const cleaned = removeRegisterGlasstrace(content);
|
|
501
498
|
if (cleaned !== content) {
|
|
502
499
|
if (!dryRun) {
|
|
503
|
-
|
|
500
|
+
fs.writeFileSync(instrPath, cleaned, "utf-8");
|
|
504
501
|
}
|
|
505
502
|
summary.push(
|
|
506
503
|
`${prefix}Removed registerGlasstrace() from instrumentation.ts`
|
|
@@ -515,10 +512,10 @@ async function runUninit(options) {
|
|
|
515
512
|
);
|
|
516
513
|
}
|
|
517
514
|
try {
|
|
518
|
-
const glasstraceDir =
|
|
519
|
-
if (
|
|
515
|
+
const glasstraceDir = path.join(projectRoot, ".glasstrace");
|
|
516
|
+
if (fs.existsSync(glasstraceDir)) {
|
|
520
517
|
if (!dryRun) {
|
|
521
|
-
|
|
518
|
+
fs.rmSync(glasstraceDir, { recursive: true, force: true });
|
|
522
519
|
}
|
|
523
520
|
summary.push(`${prefix}Removed .glasstrace/ directory`);
|
|
524
521
|
}
|
|
@@ -528,9 +525,9 @@ async function runUninit(options) {
|
|
|
528
525
|
);
|
|
529
526
|
}
|
|
530
527
|
try {
|
|
531
|
-
const envPath =
|
|
532
|
-
if (
|
|
533
|
-
const content =
|
|
528
|
+
const envPath = path.join(projectRoot, ".env.local");
|
|
529
|
+
if (fs.existsSync(envPath)) {
|
|
530
|
+
const content = fs.readFileSync(envPath, "utf-8");
|
|
534
531
|
const existingKey = readEnvLocalApiKey(content);
|
|
535
532
|
const hasDevKey = isDevApiKey(existingKey);
|
|
536
533
|
let proceed = true;
|
|
@@ -563,12 +560,12 @@ async function runUninit(options) {
|
|
|
563
560
|
const result = filtered.join("\n");
|
|
564
561
|
if (result.trim().length === 0) {
|
|
565
562
|
if (!dryRun) {
|
|
566
|
-
|
|
563
|
+
fs.unlinkSync(envPath);
|
|
567
564
|
}
|
|
568
565
|
summary.push(`${prefix}Deleted .env.local (no remaining entries)`);
|
|
569
566
|
} else {
|
|
570
567
|
if (!dryRun) {
|
|
571
|
-
|
|
568
|
+
fs.writeFileSync(envPath, result, "utf-8");
|
|
572
569
|
}
|
|
573
570
|
let devKeyAnnotation = "";
|
|
574
571
|
if (devKeyPath === "interactive-confirmed") {
|
|
@@ -591,9 +588,9 @@ async function runUninit(options) {
|
|
|
591
588
|
);
|
|
592
589
|
}
|
|
593
590
|
try {
|
|
594
|
-
const gitignorePath =
|
|
595
|
-
if (
|
|
596
|
-
const content =
|
|
591
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
592
|
+
if (fs.existsSync(gitignorePath)) {
|
|
593
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
597
594
|
const lines = content.split("\n");
|
|
598
595
|
const mcpGitignoreEntries = /* @__PURE__ */ new Set([
|
|
599
596
|
".glasstrace/",
|
|
@@ -609,12 +606,12 @@ async function runUninit(options) {
|
|
|
609
606
|
const result = filtered.join("\n");
|
|
610
607
|
if (result.trim().length === 0) {
|
|
611
608
|
if (!dryRun) {
|
|
612
|
-
|
|
609
|
+
fs.unlinkSync(gitignorePath);
|
|
613
610
|
}
|
|
614
611
|
summary.push(`${prefix}Deleted .gitignore (no remaining entries)`);
|
|
615
612
|
} else {
|
|
616
613
|
if (!dryRun) {
|
|
617
|
-
|
|
614
|
+
fs.writeFileSync(gitignorePath, result, "utf-8");
|
|
618
615
|
}
|
|
619
616
|
summary.push(`${prefix}Removed Glasstrace entries from .gitignore`);
|
|
620
617
|
}
|
|
@@ -627,63 +624,63 @@ async function runUninit(options) {
|
|
|
627
624
|
}
|
|
628
625
|
try {
|
|
629
626
|
for (const configFile of MCP_CONFIG_FILES) {
|
|
630
|
-
const configPath =
|
|
631
|
-
if (!
|
|
627
|
+
const configPath = path.join(projectRoot, configFile);
|
|
628
|
+
if (!fs.existsSync(configPath)) {
|
|
632
629
|
continue;
|
|
633
630
|
}
|
|
634
|
-
const content =
|
|
631
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
635
632
|
const result = processJsonMcpConfig(content);
|
|
636
633
|
if (result.action === "deleted") {
|
|
637
634
|
if (!dryRun) {
|
|
638
|
-
|
|
635
|
+
fs.unlinkSync(configPath);
|
|
639
636
|
}
|
|
640
637
|
summary.push(`${prefix}Deleted ${configFile}`);
|
|
641
638
|
} else if (result.action === "removed-key" && result.content !== void 0) {
|
|
642
639
|
if (!dryRun) {
|
|
643
|
-
|
|
640
|
+
fs.writeFileSync(configPath, result.content, "utf-8");
|
|
644
641
|
}
|
|
645
642
|
summary.push(`${prefix}Removed glasstrace from ${configFile}`);
|
|
646
643
|
}
|
|
647
644
|
}
|
|
648
|
-
const codexConfigPath =
|
|
649
|
-
if (
|
|
650
|
-
const content =
|
|
645
|
+
const codexConfigPath = path.join(projectRoot, ".codex", "config.toml");
|
|
646
|
+
if (fs.existsSync(codexConfigPath)) {
|
|
647
|
+
const content = fs.readFileSync(codexConfigPath, "utf-8");
|
|
651
648
|
const tomlResult = processTomlMcpConfig(content);
|
|
652
649
|
if (tomlResult.action === "deleted") {
|
|
653
650
|
if (!dryRun) {
|
|
654
|
-
|
|
651
|
+
fs.unlinkSync(codexConfigPath);
|
|
655
652
|
}
|
|
656
653
|
summary.push(`${prefix}Deleted .codex/config.toml`);
|
|
657
654
|
} else if (tomlResult.action === "removed-section" && tomlResult.content !== void 0) {
|
|
658
655
|
if (!dryRun) {
|
|
659
|
-
|
|
656
|
+
fs.writeFileSync(codexConfigPath, tomlResult.content, "utf-8");
|
|
660
657
|
}
|
|
661
658
|
summary.push(`${prefix}Removed glasstrace from .codex/config.toml`);
|
|
662
659
|
}
|
|
663
660
|
}
|
|
664
|
-
const hasWindsurfMarkers =
|
|
661
|
+
const hasWindsurfMarkers = fs.existsSync(path.join(projectRoot, ".windsurfrules")) || fs.existsSync(path.join(projectRoot, ".windsurf"));
|
|
665
662
|
if (hasWindsurfMarkers) {
|
|
666
|
-
const windsurfConfigPath =
|
|
663
|
+
const windsurfConfigPath = path.join(
|
|
667
664
|
os.homedir(),
|
|
668
665
|
".codeium",
|
|
669
666
|
"windsurf",
|
|
670
667
|
"mcp_config.json"
|
|
671
668
|
);
|
|
672
|
-
if (
|
|
673
|
-
const content =
|
|
669
|
+
if (fs.existsSync(windsurfConfigPath)) {
|
|
670
|
+
const content = fs.readFileSync(windsurfConfigPath, "utf-8");
|
|
674
671
|
const windsurfResult = processJsonMcpConfig(content);
|
|
675
672
|
const home = os.homedir();
|
|
676
673
|
const displayPath = windsurfConfigPath.startsWith(home) ? "~" + windsurfConfigPath.slice(home.length) : windsurfConfigPath;
|
|
677
674
|
if (windsurfResult.action === "deleted") {
|
|
678
675
|
if (!dryRun) {
|
|
679
|
-
|
|
676
|
+
fs.unlinkSync(windsurfConfigPath);
|
|
680
677
|
}
|
|
681
678
|
summary.push(
|
|
682
679
|
`${prefix}Deleted global Windsurf config (${displayPath})`
|
|
683
680
|
);
|
|
684
681
|
} else if (windsurfResult.action === "removed-key" && windsurfResult.content !== void 0) {
|
|
685
682
|
if (!dryRun) {
|
|
686
|
-
|
|
683
|
+
fs.writeFileSync(windsurfConfigPath, windsurfResult.content, "utf-8");
|
|
687
684
|
}
|
|
688
685
|
summary.push(
|
|
689
686
|
`${prefix}Removed glasstrace from global Windsurf config (${displayPath})`
|
|
@@ -698,21 +695,21 @@ async function runUninit(options) {
|
|
|
698
695
|
}
|
|
699
696
|
try {
|
|
700
697
|
for (const infoFile of AGENT_INFO_FILES) {
|
|
701
|
-
const filePath =
|
|
702
|
-
if (!
|
|
698
|
+
const filePath = path.join(projectRoot, infoFile);
|
|
699
|
+
if (!fs.existsSync(filePath)) {
|
|
703
700
|
continue;
|
|
704
701
|
}
|
|
705
|
-
const content =
|
|
702
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
706
703
|
const result = removeMarkerSection(content);
|
|
707
704
|
if (result.removed) {
|
|
708
705
|
if (result.content.trim().length === 0) {
|
|
709
706
|
if (!dryRun) {
|
|
710
|
-
|
|
707
|
+
fs.unlinkSync(filePath);
|
|
711
708
|
}
|
|
712
709
|
summary.push(`${prefix}Deleted ${infoFile} (only contained Glasstrace section)`);
|
|
713
710
|
} else {
|
|
714
711
|
if (!dryRun) {
|
|
715
|
-
|
|
712
|
+
fs.writeFileSync(filePath, result.content, "utf-8");
|
|
716
713
|
}
|
|
717
714
|
summary.push(`${prefix}Removed Glasstrace section from ${infoFile}`);
|
|
718
715
|
}
|