@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.
Files changed (78) hide show
  1. package/README.md +84 -1
  2. package/dist/adapters/drizzle.js +2 -5
  3. package/dist/adapters/drizzle.js.map +1 -1
  4. package/dist/{chunk-PD2SKFQQ.js → chunk-55FBXXER.js} +4 -8
  5. package/dist/{chunk-PD2SKFQQ.js.map → chunk-55FBXXER.js.map} +1 -1
  6. package/dist/chunk-5C2TJFLB.js +851 -0
  7. package/dist/chunk-5C2TJFLB.js.map +1 -0
  8. package/dist/{chunk-YMEXDDTA.js → chunk-7JBKXSBU.js} +3 -99
  9. package/dist/chunk-7JBKXSBU.js.map +1 -0
  10. package/dist/{chunk-2LDBR3F3.js → chunk-BANTDXUT.js} +15 -74
  11. package/dist/chunk-BANTDXUT.js.map +1 -0
  12. package/dist/{chunk-ZNOD6FC7.js → chunk-CTJI2YKA.js} +8 -15
  13. package/dist/{chunk-ZNOD6FC7.js.map → chunk-CTJI2YKA.js.map} +1 -1
  14. package/dist/{chunk-WK7MPK2T.js → chunk-DQ25VOKK.js} +1 -89
  15. package/dist/chunk-DQ25VOKK.js.map +1 -0
  16. package/dist/{chunk-BL3YDC6V.js → chunk-DXRZKKSO.js} +1 -6
  17. package/dist/{chunk-BL3YDC6V.js.map → chunk-DXRZKKSO.js.map} +1 -1
  18. package/dist/{chunk-BGZ7J74D.js → chunk-NSBPE2FW.js} +2 -16
  19. package/dist/{chunk-A2AZL6MZ.js → chunk-O63DJKIJ.js} +169 -18
  20. package/dist/chunk-O63DJKIJ.js.map +1 -0
  21. package/dist/{chunk-ECEN724Y.js → chunk-TM5NKZTO.js} +4 -8
  22. package/dist/{chunk-ECEN724Y.js.map → chunk-TM5NKZTO.js.map} +1 -1
  23. package/dist/chunk-VUZCLMIX.js +57 -0
  24. package/dist/chunk-VUZCLMIX.js.map +1 -0
  25. package/dist/{chunk-OSXIUKD5.js → chunk-WZXVS2EO.js} +1 -6
  26. package/dist/{chunk-OSXIUKD5.js.map → chunk-WZXVS2EO.js.map} +1 -1
  27. package/dist/{chunk-ROFOJQWN.js → chunk-XNDHQN4S.js} +7 -11
  28. package/dist/{chunk-ROFOJQWN.js.map → chunk-XNDHQN4S.js.map} +1 -1
  29. package/dist/cli/init.cjs +673 -161
  30. package/dist/cli/init.cjs.map +1 -1
  31. package/dist/cli/init.d.cts +54 -1
  32. package/dist/cli/init.d.ts +54 -1
  33. package/dist/cli/init.js +146 -37
  34. package/dist/cli/init.js.map +1 -1
  35. package/dist/cli/mcp-add.cjs +16 -16
  36. package/dist/cli/mcp-add.cjs.map +1 -1
  37. package/dist/cli/mcp-add.js +10 -13
  38. package/dist/cli/mcp-add.js.map +1 -1
  39. package/dist/cli/status.cjs +2 -2
  40. package/dist/cli/status.js +4 -7
  41. package/dist/cli/status.js.map +1 -1
  42. package/dist/cli/uninit.cjs +56 -59
  43. package/dist/cli/uninit.cjs.map +1 -1
  44. package/dist/cli/uninit.js +4 -4
  45. package/dist/cli/validate.cjs +2 -2
  46. package/dist/cli/validate.js +3 -6
  47. package/dist/cli/validate.js.map +1 -1
  48. package/dist/{esm-MDK7CZID.js → esm-KBPHCVB4.js} +3 -3
  49. package/dist/{getMachineId-bsd-4NIRBWME.js → getMachineId-bsd-345PYXFX.js} +4 -7
  50. package/dist/{getMachineId-bsd-4NIRBWME.js.map → getMachineId-bsd-345PYXFX.js.map} +1 -1
  51. package/dist/{getMachineId-darwin-2XNOCCJQ.js → getMachineId-darwin-5L2D25AD.js} +4 -7
  52. package/dist/{getMachineId-darwin-2XNOCCJQ.js.map → getMachineId-darwin-5L2D25AD.js.map} +1 -1
  53. package/dist/{getMachineId-linux-V6YSQEY7.js → getMachineId-linux-KJR4P5HN.js} +3 -6
  54. package/dist/{getMachineId-linux-V6YSQEY7.js.map → getMachineId-linux-KJR4P5HN.js.map} +1 -1
  55. package/dist/{getMachineId-unsupported-4FKBJNVO.js → getMachineId-unsupported-NDNXDYDY.js} +3 -6
  56. package/dist/{getMachineId-unsupported-4FKBJNVO.js.map → getMachineId-unsupported-NDNXDYDY.js.map} +1 -1
  57. package/dist/{getMachineId-win-WLRZBKVG.js → getMachineId-win-T7PJNJXG.js} +4 -7
  58. package/dist/{getMachineId-win-WLRZBKVG.js.map → getMachineId-win-T7PJNJXG.js.map} +1 -1
  59. package/dist/index.cjs +449 -461
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.d.cts +38 -3
  62. package/dist/index.d.ts +38 -3
  63. package/dist/index.js +195 -701
  64. package/dist/index.js.map +1 -1
  65. package/dist/{monorepo-YILKGQXQ.js → monorepo-N5Z63XP7.js} +4 -4
  66. package/dist/{source-map-uploader-3GWUQDTS.js → source-map-uploader-MUZPI2S5.js} +5 -4
  67. package/dist/source-map-uploader-MUZPI2S5.js.map +1 -0
  68. package/package.json +1 -1
  69. package/dist/chunk-2LDBR3F3.js.map +0 -1
  70. package/dist/chunk-A2AZL6MZ.js.map +0 -1
  71. package/dist/chunk-BGZ7J74D.js.map +0 -1
  72. package/dist/chunk-UPS5BGER.js +0 -182
  73. package/dist/chunk-UPS5BGER.js.map +0 -1
  74. package/dist/chunk-WK7MPK2T.js.map +0 -1
  75. package/dist/chunk-YMEXDDTA.js.map +0 -1
  76. /package/dist/{esm-MDK7CZID.js.map → chunk-NSBPE2FW.js.map} +0 -0
  77. /package/dist/{monorepo-YILKGQXQ.js.map → esm-KBPHCVB4.js.map} +0 -0
  78. /package/dist/{source-map-uploader-3GWUQDTS.js.map → monorepo-N5Z63XP7.js.map} +0 -0
@@ -5,28 +5,25 @@ import {
5
5
  injectInfoSection,
6
6
  updateGitignore,
7
7
  writeMcpConfig
8
- } from "../chunk-ZNOD6FC7.js";
8
+ } from "../chunk-CTJI2YKA.js";
9
9
  import {
10
10
  readAnonKey
11
- } from "../chunk-ECEN724Y.js";
12
- import "../chunk-YMEXDDTA.js";
11
+ } from "../chunk-TM5NKZTO.js";
12
+ import "../chunk-7JBKXSBU.js";
13
13
  import {
14
14
  scaffoldMcpMarker
15
- } from "../chunk-A2AZL6MZ.js";
15
+ } from "../chunk-O63DJKIJ.js";
16
16
  import {
17
17
  MCP_ENDPOINT,
18
18
  formatAgentName
19
- } from "../chunk-BL3YDC6V.js";
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
- init_esm_shims();
26
- import { execFile as execFileCb } from "child_process";
27
- import * as fs from "fs";
28
- import * as path from "path";
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) {
@@ -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":[]}
@@ -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"];
@@ -1,14 +1,11 @@
1
1
  import {
2
2
  NEXT_CONFIG_NAMES
3
- } from "../chunk-BL3YDC6V.js";
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
- init_esm_shims();
10
- import * as fs from "fs";
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 = [
@@ -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":[]}
@@ -45,17 +45,14 @@ __export(uninit_exports, {
45
45
  writeShutdownMarker: () => writeShutdownMarker
46
46
  });
47
47
  module.exports = __toCommonJS(uninit_exports);
48
- var fs2 = __toESM(require("fs"), 1);
49
- var os = __toESM(require("os"), 1);
50
- var path2 = __toESM(require("path"), 1);
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 = path2.join(projectRoot, ".glasstrace");
385
- if (!fs2.existsSync(dirPath)) {
381
+ const dirPath = path.join(projectRoot, ".glasstrace");
382
+ if (!fs.existsSync(dirPath)) {
386
383
  return false;
387
384
  }
388
- const markerPath = path2.join(dirPath, "shutdown-requested");
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
- fs2.writeFileSync(tmpPath, body, { encoding: "utf-8", mode: 384 });
389
+ fs.writeFileSync(tmpPath, body, { encoding: "utf-8", mode: 384 });
393
390
  try {
394
- fs2.chmodSync(tmpPath, 384);
391
+ fs.chmodSync(tmpPath, 384);
395
392
  } catch {
396
393
  }
397
- fs2.renameSync(tmpPath, markerPath);
394
+ fs.renameSync(tmpPath, markerPath);
398
395
  return true;
399
396
  } catch {
400
397
  try {
401
- fs2.unlinkSync(tmpPath);
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 = path2.join(projectRoot, ".glasstrace");
443
- if (fs2.existsSync(dirPath)) {
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 = path2.join(projectRoot, name);
456
- if (!fs2.existsSync(configPath)) {
452
+ const configPath = path.join(projectRoot, name);
453
+ if (!fs.existsSync(configPath)) {
457
454
  continue;
458
455
  }
459
- const content = fs2.readFileSync(configPath, "utf-8");
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
- fs2.writeFileSync(configPath, final, "utf-8");
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 = path2.join(projectRoot, "instrumentation.ts");
491
- if (fs2.existsSync(instrPath)) {
492
- const content = fs2.readFileSync(instrPath, "utf-8");
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
- fs2.unlinkSync(instrPath);
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
- fs2.writeFileSync(instrPath, cleaned, "utf-8");
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 = path2.join(projectRoot, ".glasstrace");
519
- if (fs2.existsSync(glasstraceDir)) {
515
+ const glasstraceDir = path.join(projectRoot, ".glasstrace");
516
+ if (fs.existsSync(glasstraceDir)) {
520
517
  if (!dryRun) {
521
- fs2.rmSync(glasstraceDir, { recursive: true, force: true });
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 = path2.join(projectRoot, ".env.local");
532
- if (fs2.existsSync(envPath)) {
533
- const content = fs2.readFileSync(envPath, "utf-8");
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
- fs2.unlinkSync(envPath);
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
- fs2.writeFileSync(envPath, result, "utf-8");
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 = path2.join(projectRoot, ".gitignore");
595
- if (fs2.existsSync(gitignorePath)) {
596
- const content = fs2.readFileSync(gitignorePath, "utf-8");
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
- fs2.unlinkSync(gitignorePath);
609
+ fs.unlinkSync(gitignorePath);
613
610
  }
614
611
  summary.push(`${prefix}Deleted .gitignore (no remaining entries)`);
615
612
  } else {
616
613
  if (!dryRun) {
617
- fs2.writeFileSync(gitignorePath, result, "utf-8");
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 = path2.join(projectRoot, configFile);
631
- if (!fs2.existsSync(configPath)) {
627
+ const configPath = path.join(projectRoot, configFile);
628
+ if (!fs.existsSync(configPath)) {
632
629
  continue;
633
630
  }
634
- const content = fs2.readFileSync(configPath, "utf-8");
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
- fs2.unlinkSync(configPath);
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
- fs2.writeFileSync(configPath, result.content, "utf-8");
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 = path2.join(projectRoot, ".codex", "config.toml");
649
- if (fs2.existsSync(codexConfigPath)) {
650
- const content = fs2.readFileSync(codexConfigPath, "utf-8");
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
- fs2.unlinkSync(codexConfigPath);
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
- fs2.writeFileSync(codexConfigPath, tomlResult.content, "utf-8");
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 = fs2.existsSync(path2.join(projectRoot, ".windsurfrules")) || fs2.existsSync(path2.join(projectRoot, ".windsurf"));
661
+ const hasWindsurfMarkers = fs.existsSync(path.join(projectRoot, ".windsurfrules")) || fs.existsSync(path.join(projectRoot, ".windsurf"));
665
662
  if (hasWindsurfMarkers) {
666
- const windsurfConfigPath = path2.join(
663
+ const windsurfConfigPath = path.join(
667
664
  os.homedir(),
668
665
  ".codeium",
669
666
  "windsurf",
670
667
  "mcp_config.json"
671
668
  );
672
- if (fs2.existsSync(windsurfConfigPath)) {
673
- const content = fs2.readFileSync(windsurfConfigPath, "utf-8");
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
- fs2.unlinkSync(windsurfConfigPath);
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
- fs2.writeFileSync(windsurfConfigPath, windsurfResult.content, "utf-8");
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 = path2.join(projectRoot, infoFile);
702
- if (!fs2.existsSync(filePath)) {
698
+ const filePath = path.join(projectRoot, infoFile);
699
+ if (!fs.existsSync(filePath)) {
703
700
  continue;
704
701
  }
705
- const content = fs2.readFileSync(filePath, "utf-8");
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
- fs2.unlinkSync(filePath);
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
- fs2.writeFileSync(filePath, result.content, "utf-8");
712
+ fs.writeFileSync(filePath, result.content, "utf-8");
716
713
  }
717
714
  summary.push(`${prefix}Removed Glasstrace section from ${infoFile}`);
718
715
  }