@glasstrace/sdk 0.15.1 → 0.17.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 +148 -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-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-2LDBR3F3.js → chunk-E33Y7BQH.js} +36 -74
- package/dist/chunk-E33Y7BQH.js.map +1 -0
- package/dist/{chunk-YMEXDDTA.js → chunk-GSGX76Q5.js} +4 -99
- package/dist/chunk-GSGX76Q5.js.map +1 -0
- package/dist/{chunk-ECEN724Y.js → chunk-J5BW7V2D.js} +4 -8
- package/dist/{chunk-ECEN724Y.js.map → chunk-J5BW7V2D.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-UUUKI65I.js +851 -0
- package/dist/chunk-UUUKI65I.js.map +1 -0
- 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 +565 -463
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -4
- package/dist/index.d.ts +93 -4
- package/dist/index.js +286 -702
- 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-26QPRSCG.js} +5 -4
- package/dist/source-map-uploader-26QPRSCG.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/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as readline from \"node:readline\";\nimport {\n scaffoldInstrumentation,\n scaffoldNextConfig,\n scaffoldEnvLocal,\n scaffoldGitignore,\n scaffoldMcpMarker,\n addCoverageMapEnv,\n mcpConfigMatches,\n readEnvLocalApiKey,\n isDevApiKey,\n} from \"./scaffolder.js\";\nimport { buildImportGraph } from \"../import-graph.js\";\nimport { getOrCreateAnonKey, readAnonKey } from \"../anon-key.js\";\nimport { detectAgents } from \"../agent-detection/detect.js\";\nimport { generateMcpConfig, generateInfoSection } from \"../agent-detection/configs.js\";\nimport { writeMcpConfig, injectInfoSection, updateGitignore } from \"../agent-detection/inject.js\";\nimport type { DetectedAgent } from \"../agent-detection/detect.js\";\nimport { MCP_ENDPOINT, NEXT_CONFIG_NAMES, formatAgentName } from \"./constants.js\";\nimport { resolveProjectRoot } from \"./monorepo.js\";\nimport {\n isInitCreatedInstrumentation,\n removeRegisterGlasstrace,\n unwrapExport,\n unwrapCJSExport,\n removeGlasstraceConfigImport,\n} from \"./uninit.js\";\n\n/**\n * Returns true if the current Node.js major version meets the minimum requirement.\n * Exported for testability — the CLI entry point uses this to gate execution.\n */\nexport function meetsNodeVersion(minMajor: number): boolean {\n const [major] = process.versions.node.split(\".\").map(Number);\n return major >= minMajor;\n}\n\n/** Options for the init command (parsed from CLI args or passed programmatically). */\nexport interface InitOptions {\n projectRoot: string;\n yes: boolean;\n coverageMap: boolean;\n /**\n * When true, skip interactive confirmation and overwrite existing\n * MCP configuration files without prompting. Preservation of the\n * anonymous key, config cache, and developer API key still applies\n * regardless of this flag — `--force` only affects the MCP diff\n * prompt (DISC-1247 Scenario 2c). Defaults to `false`.\n */\n force?: boolean;\n}\n\n/** Result of running the init command. */\nexport interface InitResult {\n exitCode: number;\n summary: string[];\n warnings: string[];\n errors: string[];\n}\n\n/**\n * Decides whether the MCP config at `configPath` should be overwritten\n * during re-init. Returns the action to take.\n *\n * - `\"write\"` — file does not exist, or existing content already matches\n * the expected content. Safe to write.\n * - `\"skip\"` — existing file differs AND the user chose to keep it, or\n * we are in a non-interactive environment without `--force`.\n * - `\"force-overwrite\"` — `force === true` (or user accepted the prompt)\n * and content differs; overwrite.\n *\n * The prompt is skipped entirely when `force` is true (non-interactive\n * overwrite) or when there is no existing file / content already matches.\n *\n * @internal Exported for unit testing only.\n */\nexport async function decideMcpConfigAction(options: {\n configPath: string | null;\n expectedContent: string;\n force: boolean;\n readFile?: (p: string) => string;\n existsSync?: (p: string) => boolean;\n prompt?: (question: string, defaultValue: boolean) => Promise<boolean>;\n}): Promise<\"write\" | \"skip\" | \"force-overwrite\"> {\n const { configPath, expectedContent, force } = options;\n if (configPath === null) return \"write\";\n\n const exists = options.existsSync ?? fs.existsSync;\n const read = options.readFile ?? ((p: string) => fs.readFileSync(p, \"utf-8\"));\n const prompt = options.prompt ?? promptYesNo;\n\n if (!exists(configPath)) return \"write\";\n\n let existingContent: string;\n try {\n existingContent = read(configPath);\n } catch {\n // Unreadable — treat as \"write\" since we can't assess drift.\n // This preserves the pre-hardening behavior for corrupt or\n // permission-restricted files.\n return \"write\";\n }\n\n if (mcpConfigMatches(existingContent, expectedContent)) {\n return \"write\";\n }\n\n if (force) {\n return \"force-overwrite\";\n }\n\n const answer = await prompt(\n `Existing MCP config at ${configPath} differs from Glasstrace's template. Overwrite?`,\n false,\n );\n return answer ? \"force-overwrite\" : \"skip\";\n}\n\n/**\n * Prompts the user with a yes/no question. Returns true for yes.\n * In non-interactive mode (no TTY), returns the default value.\n */\nasync function promptYesNo(question: string, defaultValue: boolean): Promise<boolean> {\n if (!process.stdin.isTTY) {\n return defaultValue;\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<boolean>((resolve) => {\n const suffix = defaultValue ? \" [Y/n] \" : \" [y/N] \";\n rl.question(question + suffix, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n if (trimmed === \"\") {\n resolve(defaultValue);\n return;\n }\n resolve(trimmed === \"y\" || trimmed === \"yes\");\n });\n });\n}\n\n/**\n * Identifies a scaffolding step that can be reversed during rollback.\n * Steps are tracked in execution order and rolled back in reverse.\n */\ntype CompletedStep = \"instrumentation\" | \"next-config\" | \"env-local\" | \"gitignore\";\n\n/**\n * Tracks state needed for accurate rollback of init steps.\n * Separating this from the step list allows rollback to restore\n * original file content rather than doing surgical removal.\n */\ninterface RollbackState {\n steps: CompletedStep[];\n /** Original instrumentation.ts content saved before injection.\n * When present, rollback restores this instead of using removeRegisterGlasstrace. */\n originalInstrumentationContent?: string;\n}\n\n/**\n * Removes leading blank lines that can appear after removing import lines.\n * Duplicated from uninit.ts to avoid exporting a trivial utility.\n */\nfunction cleanLeadingBlankLines(content: string): string {\n return content.replace(/^\\n{2,}/, \"\\n\");\n}\n\n/**\n * Best-effort rollback of completed init steps in reverse order.\n * Each step is individually try/caught so that a failure in one\n * rollback does not prevent the remaining steps from being attempted.\n *\n * @internal Exported for unit testing only.\n */\nexport async function rollbackSteps(\n steps: CompletedStep[],\n projectRoot: string,\n state?: Omit<RollbackState, \"steps\">,\n): Promise<void> {\n for (const step of [...steps].reverse()) {\n try {\n switch (step) {\n case \"instrumentation\": {\n const instrPath = path.join(projectRoot, \"instrumentation.ts\");\n if (fs.existsSync(instrPath)) {\n const content = fs.readFileSync(instrPath, \"utf-8\");\n if (isInitCreatedInstrumentation(content)) {\n fs.unlinkSync(instrPath);\n } else if (state?.originalInstrumentationContent !== undefined) {\n // Restore the exact original content to avoid removing\n // pre-existing imports that removeRegisterGlasstrace would strip.\n fs.writeFileSync(instrPath, state.originalInstrumentationContent, \"utf-8\");\n } else {\n const cleaned = removeRegisterGlasstrace(content);\n if (cleaned !== content) {\n fs.writeFileSync(instrPath, cleaned, \"utf-8\");\n }\n }\n }\n break;\n }\n case \"next-config\": {\n for (const name of NEXT_CONFIG_NAMES) {\n const configPath = path.join(projectRoot, name);\n if (!fs.existsSync(configPath)) {\n continue;\n }\n const content = fs.readFileSync(configPath, \"utf-8\");\n if (!content.includes(\"withGlasstraceConfig\")) {\n continue;\n }\n const isESM = name.endsWith(\".ts\") || name.endsWith(\".mjs\");\n const unwrapResult = isESM\n ? unwrapExport(content)\n : unwrapCJSExport(content);\n if (unwrapResult.unwrapped) {\n const cleaned = removeGlasstraceConfigImport(unwrapResult.content);\n fs.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), \"utf-8\");\n }\n break;\n }\n break;\n }\n case \"env-local\": {\n // Only remove GLASSTRACE_API_KEY lines — scaffoldEnvLocal (step 5)\n // only adds the API key. Removing GLASSTRACE_COVERAGE_MAP here would\n // delete a user's pre-existing coverage map setting if init fails\n // after step 5 but before the coverage map step.\n const envPath = path.join(projectRoot, \".env.local\");\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const filtered = lines.filter((line) => {\n const trimmed = line.trim();\n return !/^\\s*#?\\s*GLASSTRACE_API_KEY\\s*=/.test(trimmed);\n });\n if (filtered.length !== lines.length) {\n const result = filtered.join(\"\\n\");\n if (result.trim().length === 0) {\n fs.unlinkSync(envPath);\n } else {\n fs.writeFileSync(envPath, result, \"utf-8\");\n }\n }\n }\n break;\n }\n case \"gitignore\": {\n const gitignorePath = path.join(projectRoot, \".gitignore\");\n if (fs.existsSync(gitignorePath)) {\n const content = fs.readFileSync(gitignorePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const filtered = lines.filter(\n (line) => line.trim() !== \".glasstrace/\",\n );\n if (filtered.length !== lines.length) {\n const result = filtered.join(\"\\n\");\n if (result.trim().length === 0) {\n fs.unlinkSync(gitignorePath);\n } else {\n fs.writeFileSync(gitignorePath, result, \"utf-8\");\n }\n }\n }\n break;\n }\n }\n } catch {\n // Best-effort rollback — log nothing, continue with remaining steps\n }\n }\n}\n\n/**\n * Core init logic. Exported for testability — the CLI entry point at the\n * bottom calls this function and translates the result to process.exit().\n */\nexport async function runInit(options: InitOptions): Promise<InitResult> {\n const { yes, coverageMap } = options;\n const summary: string[] = [];\n const warnings: string[] = [];\n const errors: string[] = [];\n\n // Step 0: Resolve the correct project root (monorepo awareness)\n let projectRoot: string;\n try {\n const classification = resolveProjectRoot(options.projectRoot);\n projectRoot = classification.projectRoot;\n if (classification.isMonorepo && classification.appRelativePath) {\n summary.push(`Found Next.js app at ${classification.appRelativePath} — installing there`);\n }\n } catch (err) {\n errors.push(err instanceof Error ? err.message : String(err));\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 1: Detect package.json\n const packageJsonPath = path.join(projectRoot, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) {\n errors.push(\"No package.json found. Run this command from a Node.js project root.\");\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Track completed steps so we can roll them back if a later step fails.\n // Only steps that modify the filesystem are tracked — pre-existing state\n // (e.g., \"already-registered\") is never rolled back.\n const rollbackState: RollbackState = { steps: [] };\n\n // Step 2: Ensure instrumentation.ts has registerGlasstrace()\n try {\n // Save original content before scaffolding modifies the file.\n // This allows rollback to restore exactly what was there, rather than\n // relying on surgical removal (which can strip pre-existing imports).\n const instrPath = path.join(projectRoot, \"instrumentation.ts\");\n if (fs.existsSync(instrPath)) {\n rollbackState.originalInstrumentationContent = fs.readFileSync(instrPath, \"utf-8\");\n }\n\n const instrResult = await scaffoldInstrumentation(projectRoot);\n switch (instrResult.action) {\n case \"created\":\n summary.push(\"Created instrumentation.ts\");\n rollbackState.steps.push(\"instrumentation\");\n break;\n case \"injected\":\n summary.push(\"Added registerGlasstrace() to existing instrumentation.ts\");\n rollbackState.steps.push(\"instrumentation\");\n break;\n case \"already-registered\":\n summary.push(\"Skipped instrumentation.ts (registerGlasstrace already present)\");\n break;\n case \"unrecognized\":\n warnings.push(\n \"instrumentation.ts exists but has no recognizable register() function.\\n\" +\n \"Add this import at the top of your file:\\n\\n\" +\n ' import { registerGlasstrace } from \"@glasstrace/sdk\";\\n\\n' +\n \"Then add this as the first statement in your register() function:\\n\\n\" +\n \" registerGlasstrace();\\n\",\n );\n break;\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to write instrumentation.ts: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 4: Detect and wrap next.config.*\n try {\n const configResult = await scaffoldNextConfig(projectRoot);\n if (configResult?.modified) {\n summary.push(\"Wrapped next.config with withGlasstraceConfig()\");\n rollbackState.steps.push(\"next-config\");\n } else if (configResult === null) {\n warnings.push(\"No next.config.* found. You may need to create one for Next.js projects.\");\n } else if (configResult.reason === \"already-wrapped\") {\n summary.push(\"Skipped next.config (already contains withGlasstraceConfig)\");\n } else if (configResult.reason === \"empty-file\") {\n warnings.push(\"next.config is empty — add a Next.js configuration export to enable wrapping\");\n } else {\n warnings.push(\"next.config has no recognizable export pattern — add withGlasstraceConfig() manually\");\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to modify next.config: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 5: Update .env.local\n // DISC-1247 Scenario 6: if .env.local already defines a claimed\n // developer key (gt_dev_*), scaffoldEnvLocal preserves it and this\n // step reports the preservation so the user knows re-init did not\n // overwrite their claim.\n try {\n const envPathForCheck = path.join(projectRoot, \".env.local\");\n let existingDevKey = false;\n if (fs.existsSync(envPathForCheck)) {\n const existingContent = fs.readFileSync(envPathForCheck, \"utf-8\");\n existingDevKey = isDevApiKey(readEnvLocalApiKey(existingContent));\n }\n const envCreated = await scaffoldEnvLocal(projectRoot);\n if (envCreated) {\n summary.push(\"Updated .env.local with Glasstrace configuration\");\n rollbackState.steps.push(\"env-local\");\n } else if (existingDevKey) {\n summary.push(\n \"Preserved existing .env.local (GLASSTRACE_API_KEY contains a claimed dev key)\",\n );\n } else {\n summary.push(\"Skipped .env.local (GLASSTRACE_API_KEY already configured)\");\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to update .env.local: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 6: Update .gitignore\n try {\n const gitignoreUpdated = await scaffoldGitignore(projectRoot);\n if (gitignoreUpdated) {\n summary.push(\"Updated .gitignore with .glasstrace/\");\n rollbackState.steps.push(\"gitignore\");\n } else {\n summary.push(\"Skipped .gitignore (.glasstrace/ already listed)\");\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to update .gitignore: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 7: MCP auto-configuration\n // Use CI env vars (not TTY check) to distinguish automated builds from\n // manual CLI usage. TTY state is unreliable — piped output, test runners,\n // and IDE terminals all report isTTY=false despite being user-initiated.\n // Accept any truthy CI value (GitHub Actions, GitLab, CircleCI, Travis,\n // etc.) and also check GITHUB_ACTIONS specifically.\n const ciEnv = process.env[\"CI\"];\n const isCI =\n (typeof ciEnv === \"string\" &&\n ciEnv.trim() !== \"\" &&\n ciEnv.toLowerCase() !== \"false\" &&\n ciEnv.trim() !== \"0\") ||\n process.env[\"GITHUB_ACTIONS\"] === \"true\";\n\n try {\n // DISC-1247 Scenario 2a: preserve any existing anonymous key.\n // getOrCreateAnonKey already reads an existing key if present, so\n // re-running init never overwrites a key that may be linked to an\n // account. We explicitly check first so we can report the preservation\n // in the summary — without this, users have no feedback that re-init\n // respected their existing claim linkage.\n const preExistingAnonKey = await readAnonKey(projectRoot);\n const anonKey = await getOrCreateAnonKey(projectRoot);\n if (preExistingAnonKey !== null) {\n summary.push(\"Preserved existing .glasstrace/anon_key\");\n }\n let anyConfigWritten = false;\n\n if (isCI) {\n // Non-interactive: write only the generic .glasstrace/mcp.json.\n // CI uses `force: true` for MCP diff decisions because there's no\n // interactive terminal to prompt on — existing configs in CI\n // workspaces are rare and safe to overwrite.\n const genericAgent: DetectedAgent = {\n name: \"generic\",\n mcpConfigPath: path.join(projectRoot, \".glasstrace\", \"mcp.json\"),\n infoFilePath: null,\n cliAvailable: false,\n registrationCommand: null,\n };\n const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);\n const decision = await decideMcpConfigAction({\n configPath: genericAgent.mcpConfigPath,\n expectedContent: genericConfig,\n force: true,\n });\n if (decision !== \"skip\") {\n await writeMcpConfig(genericAgent, genericConfig, projectRoot);\n }\n if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {\n anyConfigWritten = true;\n summary.push(\"Created .glasstrace/mcp.json (CI mode)\");\n }\n } else {\n // Interactive: detect agents and configure each\n let agents: DetectedAgent[];\n try {\n agents = await detectAgents(projectRoot);\n } catch (detectErr) {\n warnings.push(\n `Agent detection failed: ${detectErr instanceof Error ? detectErr.message : String(detectErr)}. Writing generic config only.`,\n );\n // Fall back to generic-only config\n const genericAgent: DetectedAgent = {\n name: \"generic\",\n mcpConfigPath: path.join(projectRoot, \".glasstrace\", \"mcp.json\"),\n infoFilePath: null,\n cliAvailable: false,\n registrationCommand: null,\n };\n const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);\n await writeMcpConfig(genericAgent, genericConfig, projectRoot);\n if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {\n anyConfigWritten = true;\n }\n agents = [];\n }\n\n const configuredNames: string[] = [];\n\n for (const agent of agents) {\n try {\n const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);\n\n // Diff-aware MCP write (DISC-1247 Scenario 2c): if the existing\n // config differs from what init would write, prompt before\n // overwriting. `--force` (or --yes in non-interactive mode)\n // skips the prompt.\n const decision = await decideMcpConfigAction({\n configPath: agent.mcpConfigPath,\n expectedContent: configContent,\n force: options.force === true || options.yes,\n });\n\n if (decision === \"skip\") {\n summary.push(\n `Preserved existing ${agent.mcpConfigPath ?? agent.name} (user declined overwrite)`,\n );\n if (agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath)) {\n // Count existing user-edited config as \"present\" so the\n // marker file still gets written — otherwise nudges would\n // nag the user about MCP setup they consciously preserved.\n anyConfigWritten = true;\n }\n continue;\n }\n\n await writeMcpConfig(agent, configContent, projectRoot);\n\n // Verify the config file was actually written (writeMcpConfig\n // swallows permission errors and returns void)\n const configExists = agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath);\n if (!configExists) {\n continue;\n }\n\n anyConfigWritten = true;\n\n const infoContent = generateInfoSection(agent, MCP_ENDPOINT);\n if (infoContent !== \"\") {\n await injectInfoSection(agent, infoContent, projectRoot);\n }\n\n if (agent.name !== \"generic\") {\n configuredNames.push(formatAgentName(agent.name));\n }\n } catch (agentErr) {\n warnings.push(\n `Failed to configure MCP for ${agent.name}: ${agentErr instanceof Error ? agentErr.message : String(agentErr)}`,\n );\n }\n }\n\n if (configuredNames.length > 0) {\n summary.push(`Configured MCP for: ${configuredNames.join(\", \")}`);\n } else if (anyConfigWritten) {\n summary.push(\"Created .glasstrace/mcp.json (generic config)\");\n }\n }\n\n // Add MCP config files to .gitignore\n await updateGitignore(\n [\".mcp.json\", \".cursor/mcp.json\", \".gemini/settings.json\", \".codex/config.toml\"],\n projectRoot,\n );\n\n // Create marker file only if at least one config was successfully written.\n // Without this gate, a failed MCP setup would suppress future nudges,\n // leaving users stuck without MCP configuration.\n if (anyConfigWritten) {\n const markerCreated = await scaffoldMcpMarker(projectRoot, anonKey);\n if (markerCreated) {\n summary.push(\"Created .glasstrace/mcp-connected marker\");\n }\n }\n } catch (mcpErr) {\n warnings.push(\n `MCP auto-configuration failed: ${mcpErr instanceof Error ? mcpErr.message : String(mcpErr)}`,\n );\n }\n\n // Step 8: Coverage map opt-in\n let enableCoverageMap = coverageMap;\n if (!yes && !coverageMap) {\n if (process.stdin.isTTY) {\n enableCoverageMap = await promptYesNo(\n \"Would you like to enable test coverage mapping?\",\n false,\n );\n }\n }\n\n if (enableCoverageMap) {\n try {\n const added = await addCoverageMapEnv(projectRoot);\n if (added) {\n summary.push(\"Added GLASSTRACE_COVERAGE_MAP=true to .env.local\");\n }\n } catch (err) {\n warnings.push(`Failed to add coverage map env: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Step 9: Run initial import graph scan\n try {\n await buildImportGraph(projectRoot);\n summary.push(\"Completed initial import graph scan\");\n } catch (err) {\n warnings.push(`Import graph scan failed: ${err instanceof Error ? err.message : String(err)}. You can run it later.`);\n }\n }\n\n return { exitCode: 0, summary, warnings, errors };\n}\n\n/**\n * Parses CLI arguments into InitOptions.\n */\nfunction parseArgs(argv: string[]): InitOptions {\n const args = argv.slice(2); // skip node + script path\n let yes = false;\n let coverageMap = false;\n let force = false;\n\n for (const arg of args) {\n if (arg === \"--yes\" || arg === \"-y\") {\n yes = true;\n } else if (arg === \"--coverage-map\") {\n coverageMap = true;\n } else if (arg === \"--force\") {\n force = true;\n }\n }\n\n // Auto-detect non-interactive\n if (!process.stdin.isTTY) {\n yes = true;\n }\n\n return {\n projectRoot: process.cwd(),\n yes,\n coverageMap,\n force,\n };\n}\n\n/**\n * CLI entry point. Only runs when this module is executed directly\n * (not when imported for testing).\n */\nconst scriptPath =\n typeof process !== \"undefined\" && process.argv[1] !== undefined\n ? process.argv[1].replace(/\\\\/g, \"/\")\n : undefined;\n\nconst scriptBasename = scriptPath !== undefined ? path.basename(scriptPath) : undefined;\n\nconst isDirectExecution =\n scriptPath !== undefined &&\n (scriptPath.endsWith(\"/cli/init.js\") ||\n scriptPath.endsWith(\"/cli/init.ts\") ||\n scriptBasename === \"glasstrace\");\n\nif (isDirectExecution) {\n // Enforce minimum Node.js version before any command processing.\n // The engines field in package.json is advisory — npm does not enforce\n // it by default, so this provides a clear error for users on older runtimes.\n if (!meetsNodeVersion(20)) {\n process.stderr.write(\n `Error: @glasstrace/sdk requires Node.js >= 20. Current version: ${process.version}\\n`,\n );\n process.exit(1);\n }\n\n const subcommand = process.argv[2];\n\n if (subcommand === \"mcp\") {\n if (process.argv[3] === \"add\") {\n // Parse --force and --dry-run from remaining args\n const remainingArgs = process.argv.slice(4);\n const force = remainingArgs.includes(\"--force\");\n const dryRun = remainingArgs.includes(\"--dry-run\");\n\n import(\"./mcp-add.js\")\n .then(({ mcpAdd }) => mcpAdd({ force, dryRun }))\n .then((result) => {\n for (const msg of result.messages) {\n process.stderr.write(msg + \"\\n\");\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else {\n process.stderr.write(\n `Unknown mcp subcommand: ${process.argv[3] ?? \"(none)\"}\\n\\n` +\n \"Usage: glasstrace mcp add [--force] [--dry-run]\\n\",\n );\n process.exit(1);\n }\n } else if (subcommand === undefined || subcommand === \"init\" || subcommand.startsWith(\"-\")) {\n // Default: run init (handles `glasstrace`, `glasstrace init`, `glasstrace --yes`)\n const forwardedArgs = process.argv.slice(subcommand === \"init\" ? 3 : 2);\n\n // `--validate` is an init sub-mode that checks artifact consistency\n // without scaffolding (DISC-1247 Scenario 4). We dispatch to a\n // dedicated module so the main init path stays unburdened.\n //\n // Resolve the app root via the same monorepo-aware logic that\n // `runInit` and `runStatus` use so validation in a monorepo root\n // inspects the actual Next.js app directory rather than the empty\n // workspace root (addresses Codex P2 review feedback).\n if (forwardedArgs.includes(\"--validate\")) {\n let validateProjectRoot = process.cwd();\n try {\n validateProjectRoot = resolveProjectRoot(validateProjectRoot).projectRoot;\n } catch {\n // Fall back to cwd if the monorepo resolver can't find an app —\n // validate can still report orphan-artifact issues at the raw\n // cwd and will exit non-zero rather than hiding the problem.\n }\n import(\"./validate.js\")\n .then(({ runValidate }) => runValidate({ projectRoot: validateProjectRoot }))\n .then((result) => {\n for (const line of result.summary) {\n process.stderr.write(`${line}\\n`);\n }\n for (const issue of result.issues) {\n process.stderr.write(` - ${issue.message}\\n`);\n if (issue.fix) {\n process.stderr.write(` Fix: ${issue.fix}\\n`);\n }\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else {\n const options = parseArgs(process.argv);\n\n runInit(options)\n .then((result) => {\n if (result.errors.length > 0) {\n for (const err of result.errors) {\n process.stderr.write(`Error: ${err}\\n`);\n }\n }\n if (result.warnings.length > 0) {\n for (const warn of result.warnings) {\n process.stderr.write(`Warning: ${warn}\\n`);\n }\n }\n if (result.summary.length > 0) {\n process.stderr.write(\"\\nGlasstrace initialized successfully!\\n\\n\");\n for (const line of result.summary) {\n process.stderr.write(` - ${line}\\n`);\n }\n process.stderr.write(\"\\nNext steps:\\n\");\n process.stderr.write(\" 1. Start your Next.js dev server\\n\");\n process.stderr.write(\n \" 2. Glasstrace works immediately in anonymous mode\\n\",\n );\n process.stderr.write(\n \" 3. To link to your account, set GLASSTRACE_API_KEY in .env.local\\n\\n\",\n );\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n }\n } else if (subcommand === \"uninit\") {\n const remainingArgs = process.argv.slice(3);\n const dryRun = remainingArgs.includes(\"--dry-run\");\n const force = remainingArgs.includes(\"--force\");\n\n import(\"./uninit.js\")\n .then(({ runUninit }) => runUninit({ projectRoot: process.cwd(), dryRun, force }))\n .then((result) => {\n if (result.errors.length > 0) {\n for (const err of result.errors) {\n process.stderr.write(`Error: ${err}\\n`);\n }\n }\n if (result.warnings.length > 0) {\n for (const warn of result.warnings) {\n process.stderr.write(`Warning: ${warn}\\n`);\n }\n }\n if (result.summary.length > 0) {\n process.stderr.write(\"\\n\");\n for (const line of result.summary) {\n process.stderr.write(` ${line}\\n`);\n }\n process.stderr.write(\"\\n\");\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else if (subcommand === \"status\") {\n const remainingArgs = process.argv.slice(3);\n const json = remainingArgs.includes(\"--json\");\n\n Promise.all([import(\"./status.js\"), import(\"./monorepo.js\")])\n .then(([{ runStatus }, { resolveProjectRoot: resolve }]) => {\n let projectRoot = process.cwd();\n try {\n projectRoot = resolve(projectRoot).projectRoot;\n } catch {\n // Fall back to cwd if monorepo resolution fails\n }\n const result = runStatus({ projectRoot });\n if (json) {\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n } else {\n const checks = [\n [\"Installed\", result.installed],\n [\"Initialized\", result.initialized],\n [\"Instrumentation\", result.instrumentation],\n [\"Config wrapped\", result.configWrapped],\n [\"Anon key\", result.anonKey],\n [\"MCP configured\", result.mcpConfigured],\n ] as const;\n for (const [label, ok] of checks) {\n process.stderr.write(` ${ok ? \"+\" : \"-\"} ${label}\\n`);\n }\n if (result.agents.length > 0) {\n process.stderr.write(` + Agents: ${result.agents.join(\", \")}\\n`);\n } else {\n process.stderr.write(\" - Agents\\n\");\n }\n }\n process.exit(0);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else {\n process.stderr.write(\n `Unknown command: ${subcommand}\\n\\n` +\n \"Usage:\\n\" +\n \" glasstrace init [--yes] [--coverage-map] [--force] [--validate]\\n\" +\n \" glasstrace uninit [--dry-run] [--force]\\n\" +\n \" glasstrace status [--json]\\n\" +\n \" glasstrace mcp add [--force] [--dry-run]\\n\",\n );\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as readline from \"node:readline\";\nimport {\n scaffoldInstrumentation,\n scaffoldNextConfig,\n scaffoldEnvLocal,\n scaffoldGitignore,\n scaffoldMcpMarker,\n addCoverageMapEnv,\n mcpConfigMatches,\n readEnvLocalApiKey,\n isDevApiKey,\n resolveInstrumentationTarget,\n} from \"./scaffolder.js\";\nimport { buildImportGraph } from \"../import-graph.js\";\nimport { getOrCreateAnonKey, readAnonKey } from \"../anon-key.js\";\nimport { detectAgents } from \"../agent-detection/detect.js\";\nimport { generateMcpConfig, generateInfoSection } from \"../agent-detection/configs.js\";\nimport { writeMcpConfig, injectInfoSection, updateGitignore } from \"../agent-detection/inject.js\";\nimport type { DetectedAgent } from \"../agent-detection/detect.js\";\nimport { MCP_ENDPOINT, NEXT_CONFIG_NAMES, formatAgentName } from \"./constants.js\";\nimport { resolveProjectRoot } from \"./monorepo.js\";\nimport {\n isInitCreatedInstrumentation,\n removeRegisterGlasstrace,\n unwrapExport,\n unwrapCJSExport,\n removeGlasstraceConfigImport,\n} from \"./uninit.js\";\nimport { verifyInitReachable, type VerifyInitResult } from \"../init-client.js\";\nimport { resolveConfig } from \"../env-detection.js\";\n\n// Declare the tsup-injected SDK version literal. Replaced at build time\n// via `define` in tsup.config.ts. Falls back to \"0.0.0-dev\" when\n// running tests under vitest (no tsup build step).\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Returns true if the current Node.js major version meets the minimum requirement.\n * Exported for testability — the CLI entry point uses this to gate execution.\n */\nexport function meetsNodeVersion(minMajor: number): boolean {\n const [major] = process.versions.node.split(\".\").map(Number);\n return major >= minMajor;\n}\n\n/** Options for the init command (parsed from CLI args or passed programmatically). */\nexport interface InitOptions {\n projectRoot: string;\n yes: boolean;\n coverageMap: boolean;\n /**\n * When true, skip interactive confirmation and overwrite existing\n * MCP configuration files without prompting. Preservation of the\n * anonymous key, config cache, and developer API key still applies\n * regardless of this flag — `--force` only affects the MCP diff\n * prompt (DISC-1247 Scenario 2c). Defaults to `false`.\n */\n force?: boolean;\n}\n\n/** Result of running the init command. */\nexport interface InitResult {\n exitCode: number;\n summary: string[];\n warnings: string[];\n errors: string[];\n}\n\n/**\n * Decides whether the MCP config at `configPath` should be overwritten\n * during re-init. Returns the action to take.\n *\n * - `\"write\"` — file does not exist, or existing content already matches\n * the expected content. Safe to write.\n * - `\"skip\"` — existing file differs AND the user chose to keep it, or\n * we are in a non-interactive environment without `--force`.\n * - `\"force-overwrite\"` — `force === true` (or user accepted the prompt)\n * and content differs; overwrite.\n *\n * The prompt is skipped entirely when `force` is true (non-interactive\n * overwrite) or when there is no existing file / content already matches.\n *\n * @internal Exported for unit testing only.\n */\nexport async function decideMcpConfigAction(options: {\n configPath: string | null;\n expectedContent: string;\n force: boolean;\n readFile?: (p: string) => string;\n existsSync?: (p: string) => boolean;\n prompt?: (question: string, defaultValue: boolean) => Promise<boolean>;\n}): Promise<\"write\" | \"skip\" | \"force-overwrite\"> {\n const { configPath, expectedContent, force } = options;\n if (configPath === null) return \"write\";\n\n const exists = options.existsSync ?? fs.existsSync;\n const read = options.readFile ?? ((p: string) => fs.readFileSync(p, \"utf-8\"));\n const prompt = options.prompt ?? promptYesNo;\n\n if (!exists(configPath)) return \"write\";\n\n let existingContent: string;\n try {\n existingContent = read(configPath);\n } catch {\n // Unreadable — treat as \"write\" since we can't assess drift.\n // This preserves the pre-hardening behavior for corrupt or\n // permission-restricted files.\n return \"write\";\n }\n\n if (mcpConfigMatches(existingContent, expectedContent)) {\n return \"write\";\n }\n\n if (force) {\n return \"force-overwrite\";\n }\n\n const answer = await prompt(\n `Existing MCP config at ${configPath} differs from Glasstrace's template. Overwrite?`,\n false,\n );\n return answer ? \"force-overwrite\" : \"skip\";\n}\n\n/**\n * Prompts the user with a yes/no question. Returns true for yes.\n * In non-interactive mode (no TTY), returns the default value.\n */\nasync function promptYesNo(question: string, defaultValue: boolean): Promise<boolean> {\n if (!process.stdin.isTTY) {\n return defaultValue;\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<boolean>((resolve) => {\n const suffix = defaultValue ? \" [Y/n] \" : \" [y/N] \";\n rl.question(question + suffix, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n if (trimmed === \"\") {\n resolve(defaultValue);\n return;\n }\n resolve(trimmed === \"y\" || trimmed === \"yes\");\n });\n });\n}\n\n/**\n * Identifies a scaffolding step that can be reversed during rollback.\n * Steps are tracked in execution order and rolled back in reverse.\n */\ntype CompletedStep = \"instrumentation\" | \"next-config\" | \"env-local\" | \"gitignore\";\n\n/**\n * Tracks state needed for accurate rollback of init steps.\n * Separating this from the step list allows rollback to restore\n * original file content rather than doing surgical removal.\n */\ninterface RollbackState {\n steps: CompletedStep[];\n /**\n * Absolute path of the instrumentation file that the scaffolder\n * wrote to. May be either `{root}/instrumentation.ts` or\n * `{root}/src/instrumentation.ts` depending on the project layout\n * (DISC-493 Issue 1). When absent, rollback falls back to the\n * root path for backward compatibility with callers that do not\n * populate this field.\n */\n instrumentationPath?: string;\n /** Original instrumentation.ts content saved before injection.\n * When present, rollback restores this instead of using removeRegisterGlasstrace. */\n originalInstrumentationContent?: string;\n}\n\n/**\n * Removes leading blank lines that can appear after removing import lines.\n * Duplicated from uninit.ts to avoid exporting a trivial utility.\n */\nfunction cleanLeadingBlankLines(content: string): string {\n return content.replace(/^\\n{2,}/, \"\\n\");\n}\n\n/**\n * Best-effort rollback of completed init steps in reverse order.\n * Each step is individually try/caught so that a failure in one\n * rollback does not prevent the remaining steps from being attempted.\n *\n * @internal Exported for unit testing only.\n */\nexport async function rollbackSteps(\n steps: CompletedStep[],\n projectRoot: string,\n state?: Omit<RollbackState, \"steps\">,\n): Promise<void> {\n for (const step of [...steps].reverse()) {\n try {\n switch (step) {\n case \"instrumentation\": {\n // Prefer the exact path the scaffolder wrote to — the resolver\n // may have chosen `src/instrumentation.ts` on Next.js `src/`\n // layouts (DISC-493 Issue 1). Fall back to the root path for\n // callers that do not populate `instrumentationPath`.\n const instrPath =\n state?.instrumentationPath ?? path.join(projectRoot, \"instrumentation.ts\");\n if (fs.existsSync(instrPath)) {\n const content = fs.readFileSync(instrPath, \"utf-8\");\n if (isInitCreatedInstrumentation(content)) {\n fs.unlinkSync(instrPath);\n } else if (state?.originalInstrumentationContent !== undefined) {\n // Restore the exact original content to avoid removing\n // pre-existing imports that removeRegisterGlasstrace would strip.\n fs.writeFileSync(instrPath, state.originalInstrumentationContent, \"utf-8\");\n } else {\n const cleaned = removeRegisterGlasstrace(content);\n if (cleaned !== content) {\n fs.writeFileSync(instrPath, cleaned, \"utf-8\");\n }\n }\n }\n break;\n }\n case \"next-config\": {\n for (const name of NEXT_CONFIG_NAMES) {\n const configPath = path.join(projectRoot, name);\n if (!fs.existsSync(configPath)) {\n continue;\n }\n const content = fs.readFileSync(configPath, \"utf-8\");\n if (!content.includes(\"withGlasstraceConfig\")) {\n continue;\n }\n const isESM = name.endsWith(\".ts\") || name.endsWith(\".mjs\");\n const unwrapResult = isESM\n ? unwrapExport(content)\n : unwrapCJSExport(content);\n if (unwrapResult.unwrapped) {\n const cleaned = removeGlasstraceConfigImport(unwrapResult.content);\n fs.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), \"utf-8\");\n }\n break;\n }\n break;\n }\n case \"env-local\": {\n // Only remove GLASSTRACE_API_KEY lines — scaffoldEnvLocal (step 5)\n // only adds the API key. Removing GLASSTRACE_COVERAGE_MAP here would\n // delete a user's pre-existing coverage map setting if init fails\n // after step 5 but before the coverage map step.\n const envPath = path.join(projectRoot, \".env.local\");\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const filtered = lines.filter((line) => {\n const trimmed = line.trim();\n return !/^\\s*#?\\s*GLASSTRACE_API_KEY\\s*=/.test(trimmed);\n });\n if (filtered.length !== lines.length) {\n const result = filtered.join(\"\\n\");\n if (result.trim().length === 0) {\n fs.unlinkSync(envPath);\n } else {\n fs.writeFileSync(envPath, result, \"utf-8\");\n }\n }\n }\n break;\n }\n case \"gitignore\": {\n const gitignorePath = path.join(projectRoot, \".gitignore\");\n if (fs.existsSync(gitignorePath)) {\n const content = fs.readFileSync(gitignorePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const filtered = lines.filter(\n (line) => line.trim() !== \".glasstrace/\",\n );\n if (filtered.length !== lines.length) {\n const result = filtered.join(\"\\n\");\n if (result.trim().length === 0) {\n fs.unlinkSync(gitignorePath);\n } else {\n fs.writeFileSync(gitignorePath, result, \"utf-8\");\n }\n }\n }\n break;\n }\n }\n } catch {\n // Best-effort rollback — log nothing, continue with remaining steps\n }\n }\n}\n\n/**\n * Core init logic. Exported for testability — the CLI entry point at the\n * bottom calls this function and translates the result to process.exit().\n */\nexport async function runInit(options: InitOptions): Promise<InitResult> {\n const { yes, coverageMap } = options;\n const summary: string[] = [];\n const warnings: string[] = [];\n const errors: string[] = [];\n\n // Step 0: Resolve the correct project root (monorepo awareness)\n let projectRoot: string;\n try {\n const classification = resolveProjectRoot(options.projectRoot);\n projectRoot = classification.projectRoot;\n if (classification.isMonorepo && classification.appRelativePath) {\n summary.push(`Found Next.js app at ${classification.appRelativePath} — installing there`);\n }\n } catch (err) {\n errors.push(err instanceof Error ? err.message : String(err));\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 1: Detect package.json\n const packageJsonPath = path.join(projectRoot, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) {\n errors.push(\"No package.json found. Run this command from a Node.js project root.\");\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Track completed steps so we can roll them back if a later step fails.\n // Only steps that modify the filesystem are tracked — pre-existing state\n // (e.g., \"already-registered\") is never rolled back.\n const rollbackState: RollbackState = { steps: [] };\n\n // Step 2: Ensure the instrumentation file has registerGlasstrace().\n // DISC-493 Issue 1: detect `src/` layout and merge into the existing file\n // rather than overwriting the project root.\n try {\n // Pre-resolve the target so we can save the original content (for\n // faithful rollback) and record the path for the rollback state.\n const preResolved = resolveInstrumentationTarget(projectRoot);\n if (!preResolved.conflict && preResolved.target !== null) {\n rollbackState.instrumentationPath = preResolved.target;\n if (fs.existsSync(preResolved.target)) {\n rollbackState.originalInstrumentationContent = fs.readFileSync(\n preResolved.target,\n \"utf-8\",\n );\n }\n }\n\n const instrResult = await scaffoldInstrumentation(projectRoot, {\n // `--yes` implies non-interactive automation and must not hang on a\n // merge confirmation prompt. `--force` skips the prompt explicitly\n // (DISC-1247 Scenario 2c parity).\n force: options.force === true || options.yes,\n });\n // Record the exact path the scaffolder wrote to, in case the resolver\n // and scaffolder ever disagree (symlinks, TOCTOU) — rollback is more\n // accurate when it targets the file that was actually mutated.\n if (instrResult.filePath !== undefined) {\n rollbackState.instrumentationPath = instrResult.filePath;\n }\n const relativePath =\n instrResult.filePath !== undefined\n ? path.relative(projectRoot, instrResult.filePath)\n : \"instrumentation.ts\";\n switch (instrResult.action) {\n case \"created\":\n summary.push(`Created ${relativePath}`);\n rollbackState.steps.push(\"instrumentation\");\n break;\n case \"injected\":\n summary.push(`Added registerGlasstrace() to existing ${relativePath}`);\n rollbackState.steps.push(\"instrumentation\");\n break;\n case \"appended\":\n summary.push(\n `Appended register() with registerGlasstrace() to ${relativePath}`,\n );\n rollbackState.steps.push(\"instrumentation\");\n break;\n case \"already-registered\":\n summary.push(`Skipped ${relativePath} (registerGlasstrace already present)`);\n break;\n case \"skipped\":\n // User declined the merge prompt (DISC-1247 Scenario 2c parity).\n // Emit a warning so re-init output makes clear nothing changed.\n // \"--force\" here only bypasses the confirmation — the scaffolder\n // merges rather than overwriting, so the wording is deliberate.\n warnings.push(\n `Preserved ${relativePath} (merge declined; re-run with --force to apply the merge without prompting)`,\n );\n break;\n case \"conflict\": {\n // Both root and src/ instrumentation files exist — Next.js's\n // loader behavior is undefined (DISC-493 Issue 1). Refuse to\n // write a third competing file; point the user at the file to\n // merge into and tell them to remove the other.\n const primary =\n instrResult.filePath !== undefined\n ? path.relative(projectRoot, instrResult.filePath)\n : \"src/instrumentation.ts\";\n const competing =\n instrResult.conflictingPath !== undefined\n ? path.relative(projectRoot, instrResult.conflictingPath)\n : \"instrumentation.ts\";\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(\n `Both ${primary} and ${competing} exist. Next.js's loader behavior is undefined when both are present.\\n` +\n `Merge your instrumentation into ${primary} and remove ${competing}, then re-run init.`,\n );\n return { exitCode: 1, summary, warnings, errors };\n }\n case \"unrecognized\":\n warnings.push(\n `${relativePath} exists but has no recognizable register() function.\\n` +\n \"Add this import at the top of your file:\\n\\n\" +\n ' import { registerGlasstrace } from \"@glasstrace/sdk\";\\n\\n' +\n \"Then add this as the first statement in your register() function:\\n\\n\" +\n \" registerGlasstrace();\\n\",\n );\n break;\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to write instrumentation file: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 4: Detect and wrap next.config.*\n try {\n const configResult = await scaffoldNextConfig(projectRoot);\n if (configResult?.modified) {\n summary.push(\"Wrapped next.config with withGlasstraceConfig()\");\n rollbackState.steps.push(\"next-config\");\n } else if (configResult === null) {\n warnings.push(\"No next.config.* found. You may need to create one for Next.js projects.\");\n } else if (configResult.reason === \"already-wrapped\") {\n summary.push(\"Skipped next.config (already contains withGlasstraceConfig)\");\n } else if (configResult.reason === \"empty-file\") {\n warnings.push(\"next.config is empty — add a Next.js configuration export to enable wrapping\");\n } else {\n warnings.push(\"next.config has no recognizable export pattern — add withGlasstraceConfig() manually\");\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to modify next.config: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 5: Update .env.local\n // DISC-1247 Scenario 6: if .env.local already defines a claimed\n // developer key (gt_dev_*), scaffoldEnvLocal preserves it and this\n // step reports the preservation so the user knows re-init did not\n // overwrite their claim.\n try {\n const envPathForCheck = path.join(projectRoot, \".env.local\");\n let existingDevKey = false;\n if (fs.existsSync(envPathForCheck)) {\n const existingContent = fs.readFileSync(envPathForCheck, \"utf-8\");\n existingDevKey = isDevApiKey(readEnvLocalApiKey(existingContent));\n }\n const envCreated = await scaffoldEnvLocal(projectRoot);\n if (envCreated) {\n summary.push(\"Updated .env.local with Glasstrace configuration\");\n rollbackState.steps.push(\"env-local\");\n } else if (existingDevKey) {\n summary.push(\n \"Preserved existing .env.local (GLASSTRACE_API_KEY contains a claimed dev key)\",\n );\n } else {\n summary.push(\"Skipped .env.local (GLASSTRACE_API_KEY already configured)\");\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to update .env.local: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 6: Update .gitignore\n try {\n const gitignoreUpdated = await scaffoldGitignore(projectRoot);\n if (gitignoreUpdated) {\n summary.push(\"Updated .gitignore with .glasstrace/\");\n rollbackState.steps.push(\"gitignore\");\n } else {\n summary.push(\"Skipped .gitignore (.glasstrace/ already listed)\");\n }\n } catch (err) {\n await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);\n errors.push(`Failed to update .gitignore: ${err instanceof Error ? err.message : String(err)}`);\n return { exitCode: 1, summary, warnings, errors };\n }\n\n // Step 7: MCP auto-configuration\n // Use CI env vars (not TTY check) to distinguish automated builds from\n // manual CLI usage. TTY state is unreliable — piped output, test runners,\n // and IDE terminals all report isTTY=false despite being user-initiated.\n // Accept any truthy CI value (GitHub Actions, GitLab, CircleCI, Travis,\n // etc.) and also check GITHUB_ACTIONS specifically.\n const ciEnv = process.env[\"CI\"];\n const isCI =\n (typeof ciEnv === \"string\" &&\n ciEnv.trim() !== \"\" &&\n ciEnv.toLowerCase() !== \"false\" &&\n ciEnv.trim() !== \"0\") ||\n process.env[\"GITHUB_ACTIONS\"] === \"true\";\n\n try {\n // DISC-1247 Scenario 2a: preserve any existing anonymous key.\n // getOrCreateAnonKey already reads an existing key if present, so\n // re-running init never overwrites a key that may be linked to an\n // account. We explicitly check first so we can report the preservation\n // in the summary — without this, users have no feedback that re-init\n // respected their existing claim linkage.\n const preExistingAnonKey = await readAnonKey(projectRoot);\n const anonKey = await getOrCreateAnonKey(projectRoot);\n if (preExistingAnonKey !== null) {\n summary.push(\"Preserved existing .glasstrace/anon_key\");\n }\n let anyConfigWritten = false;\n\n if (isCI) {\n // Non-interactive: write only the generic .glasstrace/mcp.json.\n // CI uses `force: true` for MCP diff decisions because there's no\n // interactive terminal to prompt on — existing configs in CI\n // workspaces are rare and safe to overwrite.\n const genericAgent: DetectedAgent = {\n name: \"generic\",\n mcpConfigPath: path.join(projectRoot, \".glasstrace\", \"mcp.json\"),\n infoFilePath: null,\n cliAvailable: false,\n registrationCommand: null,\n };\n const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);\n const decision = await decideMcpConfigAction({\n configPath: genericAgent.mcpConfigPath,\n expectedContent: genericConfig,\n force: true,\n });\n if (decision !== \"skip\") {\n await writeMcpConfig(genericAgent, genericConfig, projectRoot);\n }\n if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {\n anyConfigWritten = true;\n summary.push(\"Created .glasstrace/mcp.json (CI mode)\");\n }\n } else {\n // Interactive: detect agents and configure each\n let agents: DetectedAgent[];\n try {\n agents = await detectAgents(projectRoot);\n } catch (detectErr) {\n warnings.push(\n `Agent detection failed: ${detectErr instanceof Error ? detectErr.message : String(detectErr)}. Writing generic config only.`,\n );\n // Fall back to generic-only config\n const genericAgent: DetectedAgent = {\n name: \"generic\",\n mcpConfigPath: path.join(projectRoot, \".glasstrace\", \"mcp.json\"),\n infoFilePath: null,\n cliAvailable: false,\n registrationCommand: null,\n };\n const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);\n await writeMcpConfig(genericAgent, genericConfig, projectRoot);\n if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {\n anyConfigWritten = true;\n }\n agents = [];\n }\n\n const configuredNames: string[] = [];\n\n for (const agent of agents) {\n try {\n const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);\n\n // Diff-aware MCP write (DISC-1247 Scenario 2c): if the existing\n // config differs from what init would write, prompt before\n // overwriting. `--force` (or --yes in non-interactive mode)\n // skips the prompt.\n const decision = await decideMcpConfigAction({\n configPath: agent.mcpConfigPath,\n expectedContent: configContent,\n force: options.force === true || options.yes,\n });\n\n if (decision === \"skip\") {\n summary.push(\n `Preserved existing ${agent.mcpConfigPath ?? agent.name} (user declined overwrite)`,\n );\n if (agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath)) {\n // Count existing user-edited config as \"present\" so the\n // marker file still gets written — otherwise nudges would\n // nag the user about MCP setup they consciously preserved.\n anyConfigWritten = true;\n }\n continue;\n }\n\n await writeMcpConfig(agent, configContent, projectRoot);\n\n // Verify the config file was actually written (writeMcpConfig\n // swallows permission errors and returns void)\n const configExists = agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath);\n if (!configExists) {\n continue;\n }\n\n anyConfigWritten = true;\n\n const infoContent = generateInfoSection(agent, MCP_ENDPOINT);\n if (infoContent !== \"\") {\n await injectInfoSection(agent, infoContent, projectRoot);\n }\n\n if (agent.name !== \"generic\") {\n configuredNames.push(formatAgentName(agent.name));\n }\n } catch (agentErr) {\n warnings.push(\n `Failed to configure MCP for ${agent.name}: ${agentErr instanceof Error ? agentErr.message : String(agentErr)}`,\n );\n }\n }\n\n if (configuredNames.length > 0) {\n summary.push(`Configured MCP for: ${configuredNames.join(\", \")}`);\n } else if (anyConfigWritten) {\n summary.push(\"Created .glasstrace/mcp.json (generic config)\");\n }\n }\n\n // Add MCP config files to .gitignore\n await updateGitignore(\n [\".mcp.json\", \".cursor/mcp.json\", \".gemini/settings.json\", \".codex/config.toml\"],\n projectRoot,\n );\n\n // Create marker file only if at least one config was successfully written.\n // Without this gate, a failed MCP setup would suppress future nudges,\n // leaving users stuck without MCP configuration.\n if (anyConfigWritten) {\n const markerCreated = await scaffoldMcpMarker(projectRoot, anonKey);\n if (markerCreated) {\n summary.push(\"Created .glasstrace/mcp-connected marker\");\n }\n }\n } catch (mcpErr) {\n warnings.push(\n `MCP auto-configuration failed: ${mcpErr instanceof Error ? mcpErr.message : String(mcpErr)}`,\n );\n }\n\n // Step 8: Coverage map opt-in\n let enableCoverageMap = coverageMap;\n if (!yes && !coverageMap) {\n if (process.stdin.isTTY) {\n enableCoverageMap = await promptYesNo(\n \"Would you like to enable test coverage mapping?\",\n false,\n );\n }\n }\n\n if (enableCoverageMap) {\n try {\n const added = await addCoverageMapEnv(projectRoot);\n if (added) {\n summary.push(\"Added GLASSTRACE_COVERAGE_MAP=true to .env.local\");\n }\n } catch (err) {\n warnings.push(`Failed to add coverage map env: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Step 9: Run initial import graph scan\n try {\n await buildImportGraph(projectRoot);\n summary.push(\"Completed initial import graph scan\");\n } catch (err) {\n warnings.push(`Import graph scan failed: ${err instanceof Error ? err.message : String(err)}. You can run it later.`);\n }\n }\n\n // Step 10: Blocking verification that the anon key is registered\n // server-side (DISC-493 Issue 3, DISC-494). Runs last so failures here\n // surface the exit code without blocking the file scaffolding work.\n //\n // Skipped when:\n // - `GLASSTRACE_SKIP_INIT_VERIFY=1` is set (offline installs)\n // - CI mode is active (CI builds should not reach external networks)\n // - Vitest is running (`VITEST` env var) — unit tests that don't\n // care about the network path shouldn't be forced to mock the\n // transport; tests that DO care use `_setTransportForTesting`\n // and explicitly un-set `VITEST` before calling runInit.\n const skipVerify =\n process.env[\"GLASSTRACE_SKIP_INIT_VERIFY\"] === \"1\" ||\n process.env[\"GLASSTRACE_SKIP_INIT_VERIFY\"] === \"true\" ||\n process.env[\"VITEST\"] === \"true\";\n\n if (!skipVerify && !isCI) {\n const verifyResult = await verifyAnonKeyRegistration(projectRoot);\n if (verifyResult.outcome === \"failed\") {\n errors.push(verifyResult.error);\n return { exitCode: 2, summary, warnings, errors };\n }\n if (verifyResult.outcome === \"verified\") {\n summary.push(\"Verified anon key registration with Glasstrace API\");\n } else {\n // \"skipped\": no anon key on disk means MCP auto-configuration\n // failed earlier (a warning was already emitted). Reporting\n // \"Verified ...\" here would misrepresent the state of setup —\n // a verification request was never even sent.\n summary.push(\"Skipped anon key verification (no anon key on disk)\");\n }\n }\n\n return { exitCode: 0, summary, warnings, errors };\n}\n\n/**\n * Outcome of {@link verifyAnonKeyRegistration}:\n *\n * - `\"verified\"` — the server registered the anon key (HTTP 2xx with a\n * schema-valid response body).\n * - `\"skipped\"` — no anon key was on disk, so no verification request\n * was sent. Typically means MCP auto-configuration failed earlier\n * (warnings were already emitted) — distinct from a verification\n * success.\n * - `\"failed\"` — the verification request was sent and failed.\n * `error` is a user-facing message distinguishing the failure class\n * (`fetch failed: ...`, `server rejected the key ...`, or\n * `server returned malformed response ...`) with no anon key bytes.\n */\nexport type VerifyAnonKeyOutcome =\n | { outcome: \"verified\" }\n | { outcome: \"skipped\" }\n | { outcome: \"failed\"; error: string };\n\n/**\n * Verifies that the anonymous key written by init is registered\n * server-side. Called at the end of the scaffold flow so that when it\n * fails, the user sees an actionable error rather than a misleading\n * \"initialized successfully\" followed by silent MCP authentication\n * failures (DISC-494).\n *\n * Returns a discriminated outcome so the CLI can distinguish a genuine\n * verification pass from the \"no anon key on disk\" skip case. On\n * failure the error message distinguishes three classes:\n * - \"fetch failed\" — transport error (DNS, TCP, TLS, timeout)\n * - \"server rejected the key\" — HTTP 4xx/5xx\n * - \"server returned malformed response\" — HTTP 2xx with unparseable\n * body\n *\n * The anon key is NEVER included in the returned message. Callers\n * (the CLI entry point) render it verbatim to stderr via the errors\n * array and exit non-zero.\n *\n * @internal Exported for testability.\n */\nexport async function verifyAnonKeyRegistration(\n projectRoot: string,\n): Promise<VerifyAnonKeyOutcome> {\n // Read env the same way the runtime would — scaffoldEnvLocal may have\n // written GLASSTRACE_API_KEY=gt_anon_..., so prefer the generated\n // anon key on disk as the authoritative value to verify.\n const anonKey = await readAnonKey(projectRoot);\n if (anonKey === null) {\n // No anon key on disk means MCP wasn't configured. Skip\n // verification — this is a partial install, not a verification\n // failure. The init flow already emitted warnings above. Report\n // \"skipped\" so the caller doesn't claim verification succeeded.\n return { outcome: \"skipped\" };\n }\n\n // Load the dev key from .env.local if present (for straggler linking)\n // but fall through to anon-only verification otherwise. Reading is\n // best-effort: any error leaves devKey undefined and we verify the\n // anon key in isolation.\n //\n // Use `readEnvLocalApiKey` (shared with the rest of the init flow) so\n // we match dotenv-style last-wins semantics. A hand-rolled regex here\n // would pick the FIRST `GLASSTRACE_API_KEY=` assignment, which in a\n // rotated env file would authenticate with a stale key and surface a\n // false `server rejected` failure even when the effective key is\n // valid.\n let devKey: string | undefined;\n try {\n const envPath = path.join(projectRoot, \".env.local\");\n if (fs.existsSync(envPath)) {\n const envContent = fs.readFileSync(envPath, \"utf-8\");\n const effective = readEnvLocalApiKey(envContent);\n // Only send a real dev key in the dev slot — don't double-count\n // the anon key as both keys.\n if (effective !== null && isDevApiKey(effective)) {\n devKey = effective;\n }\n }\n } catch {\n // Ignore — fall through to anon-only verification.\n }\n\n // Resolve endpoint / environment from the user's shell, then pin\n // `apiKey` to whatever we read from .env.local. `resolveConfig` uses\n // `??` to fall back to `process.env.GLASSTRACE_API_KEY` when the\n // option is undefined, which would cause verification to authenticate\n // with an unrelated stale key in shells that export\n // `GLASSTRACE_API_KEY` — producing false \"server rejected\" failures\n // even when the freshly generated anon key is valid. The explicit\n // override keeps verification tied to disk state.\n const baseConfig = resolveConfig({ apiKey: devKey });\n const config = { ...baseConfig, apiKey: devKey };\n const sdkVersion = typeof __SDK_VERSION__ === \"string\" ? __SDK_VERSION__ : \"0.0.0-dev\";\n\n const result: VerifyInitResult = await verifyInitReachable(config, anonKey, sdkVersion);\n\n if (result.ok) {\n return { outcome: \"verified\" };\n }\n\n const hint = \"Run 'npx glasstrace status' or 'npx glasstrace doctor' to diagnose.\";\n switch (result.reason) {\n case \"transport\":\n // `result.detail` is the raw cause with any leading `fetch failed: `\n // stripped by verifyInitReachable. Format once here so the output\n // matches the documented `fetch failed: <reason>` shape and never\n // renders `fetch failed (fetch failed: ...)`.\n return {\n outcome: \"failed\",\n error: `Glasstrace init verification failed: fetch failed: ${result.detail}. ${hint}`,\n };\n case \"rejected\":\n return {\n outcome: \"failed\",\n error: `Glasstrace init verification failed: server rejected the key (HTTP ${result.status}). ${hint}`,\n };\n case \"malformed\":\n return {\n outcome: \"failed\",\n error: `Glasstrace init verification failed: server returned malformed response. ${hint}`,\n };\n }\n}\n\n/**\n * Parses CLI arguments into InitOptions.\n */\nfunction parseArgs(argv: string[]): InitOptions {\n const args = argv.slice(2); // skip node + script path\n let yes = false;\n let coverageMap = false;\n let force = false;\n\n for (const arg of args) {\n if (arg === \"--yes\" || arg === \"-y\") {\n yes = true;\n } else if (arg === \"--coverage-map\") {\n coverageMap = true;\n } else if (arg === \"--force\") {\n force = true;\n }\n }\n\n // Auto-detect non-interactive\n if (!process.stdin.isTTY) {\n yes = true;\n }\n\n return {\n projectRoot: process.cwd(),\n yes,\n coverageMap,\n force,\n };\n}\n\n/**\n * CLI entry point. Only runs when this module is executed directly\n * (not when imported for testing).\n */\nconst scriptPath =\n typeof process !== \"undefined\" && process.argv[1] !== undefined\n ? process.argv[1].replace(/\\\\/g, \"/\")\n : undefined;\n\nconst scriptBasename = scriptPath !== undefined ? path.basename(scriptPath) : undefined;\n\nconst isDirectExecution =\n scriptPath !== undefined &&\n (scriptPath.endsWith(\"/cli/init.js\") ||\n scriptPath.endsWith(\"/cli/init.ts\") ||\n scriptBasename === \"glasstrace\");\n\nif (isDirectExecution) {\n // Enforce minimum Node.js version before any command processing.\n // The engines field in package.json is advisory — npm does not enforce\n // it by default, so this provides a clear error for users on older runtimes.\n if (!meetsNodeVersion(20)) {\n process.stderr.write(\n `Error: @glasstrace/sdk requires Node.js >= 20. Current version: ${process.version}\\n`,\n );\n process.exit(1);\n }\n\n const subcommand = process.argv[2];\n\n if (subcommand === \"mcp\") {\n if (process.argv[3] === \"add\") {\n // Parse --force and --dry-run from remaining args\n const remainingArgs = process.argv.slice(4);\n const force = remainingArgs.includes(\"--force\");\n const dryRun = remainingArgs.includes(\"--dry-run\");\n\n import(\"./mcp-add.js\")\n .then(({ mcpAdd }) => mcpAdd({ force, dryRun }))\n .then((result) => {\n for (const msg of result.messages) {\n process.stderr.write(msg + \"\\n\");\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else {\n process.stderr.write(\n `Unknown mcp subcommand: ${process.argv[3] ?? \"(none)\"}\\n\\n` +\n \"Usage: glasstrace mcp add [--force] [--dry-run]\\n\",\n );\n process.exit(1);\n }\n } else if (subcommand === undefined || subcommand === \"init\" || subcommand.startsWith(\"-\")) {\n // Default: run init (handles `glasstrace`, `glasstrace init`, `glasstrace --yes`)\n const forwardedArgs = process.argv.slice(subcommand === \"init\" ? 3 : 2);\n\n // `--validate` is an init sub-mode that checks artifact consistency\n // without scaffolding (DISC-1247 Scenario 4). We dispatch to a\n // dedicated module so the main init path stays unburdened.\n //\n // Resolve the app root via the same monorepo-aware logic that\n // `runInit` and `runStatus` use so validation in a monorepo root\n // inspects the actual Next.js app directory rather than the empty\n // workspace root (addresses Codex P2 review feedback).\n if (forwardedArgs.includes(\"--validate\")) {\n let validateProjectRoot = process.cwd();\n try {\n validateProjectRoot = resolveProjectRoot(validateProjectRoot).projectRoot;\n } catch {\n // Fall back to cwd if the monorepo resolver can't find an app —\n // validate can still report orphan-artifact issues at the raw\n // cwd and will exit non-zero rather than hiding the problem.\n }\n import(\"./validate.js\")\n .then(({ runValidate }) => runValidate({ projectRoot: validateProjectRoot }))\n .then((result) => {\n for (const line of result.summary) {\n process.stderr.write(`${line}\\n`);\n }\n for (const issue of result.issues) {\n process.stderr.write(` - ${issue.message}\\n`);\n if (issue.fix) {\n process.stderr.write(` Fix: ${issue.fix}\\n`);\n }\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else {\n const options = parseArgs(process.argv);\n\n runInit(options)\n .then((result) => {\n if (result.errors.length > 0) {\n for (const err of result.errors) {\n process.stderr.write(`Error: ${err}\\n`);\n }\n }\n if (result.warnings.length > 0) {\n for (const warn of result.warnings) {\n process.stderr.write(`Warning: ${warn}\\n`);\n }\n }\n if (result.summary.length > 0) {\n // Only claim success when exitCode is 0. A non-zero exit\n // means init scaffolding completed but a later step (e.g.,\n // verifyAnonKeyRegistration) failed — we must not tell the\n // user everything is fine (DISC-494 root cause).\n if (result.exitCode === 0) {\n process.stderr.write(\"\\nGlasstrace initialized successfully!\\n\\n\");\n } else {\n process.stderr.write(\"\\nGlasstrace init completed with errors.\\n\\n\");\n }\n for (const line of result.summary) {\n process.stderr.write(` - ${line}\\n`);\n }\n if (result.exitCode === 0) {\n process.stderr.write(\"\\nNext steps:\\n\");\n process.stderr.write(\" 1. Start your Next.js dev server\\n\");\n process.stderr.write(\n \" 2. Glasstrace works immediately in anonymous mode\\n\",\n );\n process.stderr.write(\n \" 3. To link to your account, set GLASSTRACE_API_KEY in .env.local\\n\\n\",\n );\n }\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n }\n } else if (subcommand === \"uninit\") {\n const remainingArgs = process.argv.slice(3);\n const dryRun = remainingArgs.includes(\"--dry-run\");\n const force = remainingArgs.includes(\"--force\");\n\n import(\"./uninit.js\")\n .then(({ runUninit }) => runUninit({ projectRoot: process.cwd(), dryRun, force }))\n .then((result) => {\n if (result.errors.length > 0) {\n for (const err of result.errors) {\n process.stderr.write(`Error: ${err}\\n`);\n }\n }\n if (result.warnings.length > 0) {\n for (const warn of result.warnings) {\n process.stderr.write(`Warning: ${warn}\\n`);\n }\n }\n if (result.summary.length > 0) {\n process.stderr.write(\"\\n\");\n for (const line of result.summary) {\n process.stderr.write(` ${line}\\n`);\n }\n process.stderr.write(\"\\n\");\n }\n process.exit(result.exitCode);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else if (subcommand === \"status\") {\n const remainingArgs = process.argv.slice(3);\n const json = remainingArgs.includes(\"--json\");\n\n Promise.all([import(\"./status.js\"), import(\"./monorepo.js\")])\n .then(([{ runStatus }, { resolveProjectRoot: resolve }]) => {\n let projectRoot = process.cwd();\n try {\n projectRoot = resolve(projectRoot).projectRoot;\n } catch {\n // Fall back to cwd if monorepo resolution fails\n }\n const result = runStatus({ projectRoot });\n if (json) {\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n } else {\n const checks = [\n [\"Installed\", result.installed],\n [\"Initialized\", result.initialized],\n [\"Instrumentation\", result.instrumentation],\n [\"Config wrapped\", result.configWrapped],\n [\"Anon key\", result.anonKey],\n [\"MCP configured\", result.mcpConfigured],\n ] as const;\n for (const [label, ok] of checks) {\n process.stderr.write(` ${ok ? \"+\" : \"-\"} ${label}\\n`);\n }\n if (result.agents.length > 0) {\n process.stderr.write(` + Agents: ${result.agents.join(\", \")}\\n`);\n } else {\n process.stderr.write(\" - Agents\\n\");\n }\n }\n process.exit(0);\n })\n .catch((err: unknown) => {\n process.stderr.write(\n `Fatal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n } else {\n process.stderr.write(\n `Unknown command: ${subcommand}\\n\\n` +\n \"Usage:\\n\" +\n \" glasstrace init [--yes] [--coverage-map] [--force] [--validate]\\n\" +\n \" glasstrace uninit [--dry-run] [--force]\\n\" +\n \" glasstrace status [--json]\\n\" +\n \" glasstrace mcp add [--force] [--dry-run]\\n\",\n );\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/mcp-add.cjs
CHANGED
|
@@ -33,10 +33,10 @@ __export(mcp_add_exports, {
|
|
|
33
33
|
mcpAdd: () => mcpAdd
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(mcp_add_exports);
|
|
36
|
-
var import_node_child_process2 = require("child_process");
|
|
37
|
-
var fs2 = __toESM(require("fs"), 1);
|
|
38
|
-
var path2 = __toESM(require("path"), 1);
|
|
39
|
-
var import_node_util = require("util");
|
|
36
|
+
var import_node_child_process2 = require("node:child_process");
|
|
37
|
+
var fs2 = __toESM(require("node:fs"), 1);
|
|
38
|
+
var path2 = __toESM(require("node:path"), 1);
|
|
39
|
+
var import_node_util = require("node:util");
|
|
40
40
|
|
|
41
41
|
// ../../node_modules/zod/v4/classic/external.js
|
|
42
42
|
var external_exports = {};
|
|
@@ -13940,8 +13940,8 @@ async function loadFsPath() {
|
|
|
13940
13940
|
if (fsPathCache !== void 0) return fsPathCache;
|
|
13941
13941
|
try {
|
|
13942
13942
|
const [fs3, path3] = await Promise.all([
|
|
13943
|
-
import("fs/promises"),
|
|
13944
|
-
import("path")
|
|
13943
|
+
import("node:fs/promises"),
|
|
13944
|
+
import("node:path")
|
|
13945
13945
|
]);
|
|
13946
13946
|
fsPathCache = { fs: fs3, path: path3 };
|
|
13947
13947
|
return fsPathCache;
|
|
@@ -13973,11 +13973,11 @@ async function readAnonKey(projectRoot) {
|
|
|
13973
13973
|
}
|
|
13974
13974
|
|
|
13975
13975
|
// src/agent-detection/detect.ts
|
|
13976
|
-
var import_node_child_process = require("child_process");
|
|
13977
|
-
var import_promises = require("fs/promises");
|
|
13978
|
-
var import_node_path = require("path");
|
|
13979
|
-
var import_node_os = require("os");
|
|
13980
|
-
var import_node_fs = require("fs");
|
|
13976
|
+
var import_node_child_process = require("node:child_process");
|
|
13977
|
+
var import_promises = require("node:fs/promises");
|
|
13978
|
+
var import_node_path = require("node:path");
|
|
13979
|
+
var import_node_os = require("node:os");
|
|
13980
|
+
var import_node_fs = require("node:fs");
|
|
13981
13981
|
var AGENT_RULES = [
|
|
13982
13982
|
{
|
|
13983
13983
|
name: "claude",
|
|
@@ -14288,8 +14288,8 @@ ${content}${m.end}
|
|
|
14288
14288
|
}
|
|
14289
14289
|
|
|
14290
14290
|
// src/agent-detection/inject.ts
|
|
14291
|
-
var import_promises2 = require("fs/promises");
|
|
14292
|
-
var import_node_path2 = require("path");
|
|
14291
|
+
var import_promises2 = require("node:fs/promises");
|
|
14292
|
+
var import_node_path2 = require("node:path");
|
|
14293
14293
|
var HTML_START = "<!-- glasstrace:mcp:start -->";
|
|
14294
14294
|
var HTML_END = "<!-- glasstrace:mcp:end -->";
|
|
14295
14295
|
var HASH_START = "# glasstrace:mcp:start";
|
|
@@ -14465,9 +14465,9 @@ async function updateGitignore(paths, projectRoot) {
|
|
|
14465
14465
|
}
|
|
14466
14466
|
|
|
14467
14467
|
// src/cli/scaffolder.ts
|
|
14468
|
-
var import_node_crypto = require("crypto");
|
|
14469
|
-
var fs = __toESM(require("fs"), 1);
|
|
14470
|
-
var path = __toESM(require("path"), 1);
|
|
14468
|
+
var import_node_crypto = require("node:crypto");
|
|
14469
|
+
var fs = __toESM(require("node:fs"), 1);
|
|
14470
|
+
var path = __toESM(require("node:path"), 1);
|
|
14471
14471
|
|
|
14472
14472
|
// src/cli/constants.ts
|
|
14473
14473
|
var MCP_ENDPOINT = "https://api.glasstrace.dev/mcp";
|