@glasstrace/sdk 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/drizzle.js +1 -1
- package/dist/{chunk-ZRNG36LU.js → chunk-6GRNJ722.js} +38 -17
- package/dist/chunk-6GRNJ722.js.map +1 -0
- package/dist/chunk-IPGOKORJ.js +580 -0
- package/dist/chunk-IPGOKORJ.js.map +1 -0
- package/dist/{chunk-5MAHIPFH.js → chunk-LW7DPKBA.js} +2 -2
- package/dist/{chunk-KOYJ2UQE.js → chunk-MSMOH6IH.js} +108 -38
- package/dist/chunk-MSMOH6IH.js.map +1 -0
- package/dist/chunk-NSBPE2FW.js +17 -0
- package/dist/{chunk-O3Y45VGV.js → chunk-OKIP4SRG.js} +5 -3
- package/dist/{chunk-O3Y45VGV.js.map → chunk-OKIP4SRG.js.map} +1 -1
- package/dist/cli/init.cjs +457 -330
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +25 -1
- package/dist/cli/init.d.ts +25 -1
- package/dist/cli/init.js +114 -4
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +63 -47
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +3 -3
- package/dist/cli/uninit.js +15 -564
- package/dist/cli/uninit.js.map +1 -1
- package/dist/{esm-POMEQPKL.js → esm-KBPHCVB4.js} +2 -2
- package/dist/{getMachineId-bsd-TC3JSTY5.js → getMachineId-bsd-345PYXFX.js} +2 -2
- package/dist/{getMachineId-darwin-2SUKQCE6.js → getMachineId-darwin-5L2D25AD.js} +2 -2
- package/dist/{getMachineId-linux-PNAFHLXH.js → getMachineId-linux-KJR4P5HN.js} +2 -2
- package/dist/{getMachineId-unsupported-L2MNYW3W.js → getMachineId-unsupported-NDNXDYDY.js} +2 -2
- package/dist/{getMachineId-win-D6D42WOQ.js → getMachineId-win-T7PJNJXG.js} +2 -2
- package/dist/index.cjs +327 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -11
- package/dist/index.d.ts +75 -11
- package/dist/index.js +159 -82
- package/dist/index.js.map +1 -1
- package/dist/{source-map-uploader-OA5NCDOK.js → source-map-uploader-ZFCYOURS.js} +6 -4
- package/package.json +1 -1
- package/dist/chunk-KOYJ2UQE.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-ZRNG36LU.js.map +0 -1
- /package/dist/{chunk-5MAHIPFH.js.map → chunk-LW7DPKBA.js.map} +0 -0
- /package/dist/{chunk-PZ5AY32C.js.map → chunk-NSBPE2FW.js.map} +0 -0
- /package/dist/{esm-POMEQPKL.js.map → esm-KBPHCVB4.js.map} +0 -0
- /package/dist/{getMachineId-bsd-TC3JSTY5.js.map → getMachineId-bsd-345PYXFX.js.map} +0 -0
- /package/dist/{getMachineId-darwin-2SUKQCE6.js.map → getMachineId-darwin-5L2D25AD.js.map} +0 -0
- /package/dist/{getMachineId-linux-PNAFHLXH.js.map → getMachineId-linux-KJR4P5HN.js.map} +0 -0
- /package/dist/{getMachineId-unsupported-L2MNYW3W.js.map → getMachineId-unsupported-NDNXDYDY.js.map} +0 -0
- /package/dist/{getMachineId-win-D6D42WOQ.js.map → getMachineId-win-T7PJNJXG.js.map} +0 -0
- /package/dist/{source-map-uploader-OA5NCDOK.js.map → source-map-uploader-ZFCYOURS.js.map} +0 -0
package/dist/cli/init.d.cts
CHANGED
|
@@ -17,10 +17,34 @@ interface InitResult {
|
|
|
17
17
|
warnings: string[];
|
|
18
18
|
errors: string[];
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Identifies a scaffolding step that can be reversed during rollback.
|
|
22
|
+
* Steps are tracked in execution order and rolled back in reverse.
|
|
23
|
+
*/
|
|
24
|
+
type CompletedStep = "instrumentation" | "next-config" | "env-local" | "gitignore";
|
|
25
|
+
/**
|
|
26
|
+
* Tracks state needed for accurate rollback of init steps.
|
|
27
|
+
* Separating this from the step list allows rollback to restore
|
|
28
|
+
* original file content rather than doing surgical removal.
|
|
29
|
+
*/
|
|
30
|
+
interface RollbackState {
|
|
31
|
+
steps: CompletedStep[];
|
|
32
|
+
/** Original instrumentation.ts content saved before injection.
|
|
33
|
+
* When present, rollback restores this instead of using removeRegisterGlasstrace. */
|
|
34
|
+
originalInstrumentationContent?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Best-effort rollback of completed init steps in reverse order.
|
|
38
|
+
* Each step is individually try/caught so that a failure in one
|
|
39
|
+
* rollback does not prevent the remaining steps from being attempted.
|
|
40
|
+
*
|
|
41
|
+
* @internal Exported for unit testing only.
|
|
42
|
+
*/
|
|
43
|
+
declare function rollbackSteps(steps: CompletedStep[], projectRoot: string, state?: Omit<RollbackState, "steps">): Promise<void>;
|
|
20
44
|
/**
|
|
21
45
|
* Core init logic. Exported for testability — the CLI entry point at the
|
|
22
46
|
* bottom calls this function and translates the result to process.exit().
|
|
23
47
|
*/
|
|
24
48
|
declare function runInit(options: InitOptions): Promise<InitResult>;
|
|
25
49
|
|
|
26
|
-
export { type InitOptions, type InitResult, meetsNodeVersion, runInit };
|
|
50
|
+
export { type InitOptions, type InitResult, meetsNodeVersion, rollbackSteps, runInit };
|
package/dist/cli/init.d.ts
CHANGED
|
@@ -17,10 +17,34 @@ interface InitResult {
|
|
|
17
17
|
warnings: string[];
|
|
18
18
|
errors: string[];
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Identifies a scaffolding step that can be reversed during rollback.
|
|
22
|
+
* Steps are tracked in execution order and rolled back in reverse.
|
|
23
|
+
*/
|
|
24
|
+
type CompletedStep = "instrumentation" | "next-config" | "env-local" | "gitignore";
|
|
25
|
+
/**
|
|
26
|
+
* Tracks state needed for accurate rollback of init steps.
|
|
27
|
+
* Separating this from the step list allows rollback to restore
|
|
28
|
+
* original file content rather than doing surgical removal.
|
|
29
|
+
*/
|
|
30
|
+
interface RollbackState {
|
|
31
|
+
steps: CompletedStep[];
|
|
32
|
+
/** Original instrumentation.ts content saved before injection.
|
|
33
|
+
* When present, rollback restores this instead of using removeRegisterGlasstrace. */
|
|
34
|
+
originalInstrumentationContent?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Best-effort rollback of completed init steps in reverse order.
|
|
38
|
+
* Each step is individually try/caught so that a failure in one
|
|
39
|
+
* rollback does not prevent the remaining steps from being attempted.
|
|
40
|
+
*
|
|
41
|
+
* @internal Exported for unit testing only.
|
|
42
|
+
*/
|
|
43
|
+
declare function rollbackSteps(steps: CompletedStep[], projectRoot: string, state?: Omit<RollbackState, "steps">): Promise<void>;
|
|
20
44
|
/**
|
|
21
45
|
* Core init logic. Exported for testability — the CLI entry point at the
|
|
22
46
|
* bottom calls this function and translates the result to process.exit().
|
|
23
47
|
*/
|
|
24
48
|
declare function runInit(options: InitOptions): Promise<InitResult>;
|
|
25
49
|
|
|
26
|
-
export { type InitOptions, type InitResult, meetsNodeVersion, runInit };
|
|
50
|
+
export { type InitOptions, type InitResult, meetsNodeVersion, rollbackSteps, runInit };
|
package/dist/cli/init.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
buildImportGraph
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-LW7DPKBA.js";
|
|
5
|
+
import {
|
|
6
|
+
isInitCreatedInstrumentation,
|
|
7
|
+
removeGlasstraceConfigImport,
|
|
8
|
+
removeRegisterGlasstrace,
|
|
9
|
+
unwrapCJSExport,
|
|
10
|
+
unwrapExport
|
|
11
|
+
} from "../chunk-IPGOKORJ.js";
|
|
5
12
|
import {
|
|
6
13
|
addCoverageMapEnv,
|
|
7
14
|
detectAgents,
|
|
@@ -18,14 +25,14 @@ import {
|
|
|
18
25
|
} from "../chunk-4NDQPWDJ.js";
|
|
19
26
|
import {
|
|
20
27
|
getOrCreateAnonKey
|
|
21
|
-
} from "../chunk-
|
|
22
|
-
import "../chunk-
|
|
28
|
+
} from "../chunk-6GRNJ722.js";
|
|
29
|
+
import "../chunk-OKIP4SRG.js";
|
|
23
30
|
import {
|
|
24
31
|
MCP_ENDPOINT,
|
|
25
32
|
NEXT_CONFIG_NAMES,
|
|
26
33
|
formatAgentName
|
|
27
34
|
} from "../chunk-DXRZKKSO.js";
|
|
28
|
-
import "../chunk-
|
|
35
|
+
import "../chunk-NSBPE2FW.js";
|
|
29
36
|
|
|
30
37
|
// src/cli/init.ts
|
|
31
38
|
import * as fs2 from "fs";
|
|
@@ -289,6 +296,94 @@ async function promptYesNo(question, defaultValue) {
|
|
|
289
296
|
});
|
|
290
297
|
});
|
|
291
298
|
}
|
|
299
|
+
function cleanLeadingBlankLines(content) {
|
|
300
|
+
return content.replace(/^\n{2,}/, "\n");
|
|
301
|
+
}
|
|
302
|
+
async function rollbackSteps(steps, projectRoot, state) {
|
|
303
|
+
for (const step of [...steps].reverse()) {
|
|
304
|
+
try {
|
|
305
|
+
switch (step) {
|
|
306
|
+
case "instrumentation": {
|
|
307
|
+
const instrPath = path2.join(projectRoot, "instrumentation.ts");
|
|
308
|
+
if (fs2.existsSync(instrPath)) {
|
|
309
|
+
const content = fs2.readFileSync(instrPath, "utf-8");
|
|
310
|
+
if (isInitCreatedInstrumentation(content)) {
|
|
311
|
+
fs2.unlinkSync(instrPath);
|
|
312
|
+
} else if (state?.originalInstrumentationContent !== void 0) {
|
|
313
|
+
fs2.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
|
|
314
|
+
} else {
|
|
315
|
+
const cleaned = removeRegisterGlasstrace(content);
|
|
316
|
+
if (cleaned !== content) {
|
|
317
|
+
fs2.writeFileSync(instrPath, cleaned, "utf-8");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
case "next-config": {
|
|
324
|
+
for (const name of NEXT_CONFIG_NAMES) {
|
|
325
|
+
const configPath = path2.join(projectRoot, name);
|
|
326
|
+
if (!fs2.existsSync(configPath)) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
330
|
+
if (!content.includes("withGlasstraceConfig")) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const isESM = name.endsWith(".ts") || name.endsWith(".mjs");
|
|
334
|
+
const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
|
|
335
|
+
if (unwrapResult.unwrapped) {
|
|
336
|
+
const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
|
|
337
|
+
fs2.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), "utf-8");
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
case "env-local": {
|
|
344
|
+
const envPath = path2.join(projectRoot, ".env.local");
|
|
345
|
+
if (fs2.existsSync(envPath)) {
|
|
346
|
+
const content = fs2.readFileSync(envPath, "utf-8");
|
|
347
|
+
const lines = content.split("\n");
|
|
348
|
+
const filtered = lines.filter((line) => {
|
|
349
|
+
const trimmed = line.trim();
|
|
350
|
+
return !/^\s*#?\s*GLASSTRACE_API_KEY\s*=/.test(trimmed);
|
|
351
|
+
});
|
|
352
|
+
if (filtered.length !== lines.length) {
|
|
353
|
+
const result = filtered.join("\n");
|
|
354
|
+
if (result.trim().length === 0) {
|
|
355
|
+
fs2.unlinkSync(envPath);
|
|
356
|
+
} else {
|
|
357
|
+
fs2.writeFileSync(envPath, result, "utf-8");
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
case "gitignore": {
|
|
364
|
+
const gitignorePath = path2.join(projectRoot, ".gitignore");
|
|
365
|
+
if (fs2.existsSync(gitignorePath)) {
|
|
366
|
+
const content = fs2.readFileSync(gitignorePath, "utf-8");
|
|
367
|
+
const lines = content.split("\n");
|
|
368
|
+
const filtered = lines.filter(
|
|
369
|
+
(line) => line.trim() !== ".glasstrace/"
|
|
370
|
+
);
|
|
371
|
+
if (filtered.length !== lines.length) {
|
|
372
|
+
const result = filtered.join("\n");
|
|
373
|
+
if (result.trim().length === 0) {
|
|
374
|
+
fs2.unlinkSync(gitignorePath);
|
|
375
|
+
} else {
|
|
376
|
+
fs2.writeFileSync(gitignorePath, result, "utf-8");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
292
387
|
async function runInit(options) {
|
|
293
388
|
const { yes, coverageMap } = options;
|
|
294
389
|
const summary = [];
|
|
@@ -310,14 +405,21 @@ async function runInit(options) {
|
|
|
310
405
|
errors.push("No package.json found. Run this command from a Node.js project root.");
|
|
311
406
|
return { exitCode: 1, summary, warnings, errors };
|
|
312
407
|
}
|
|
408
|
+
const rollbackState = { steps: [] };
|
|
313
409
|
try {
|
|
410
|
+
const instrPath = path2.join(projectRoot, "instrumentation.ts");
|
|
411
|
+
if (fs2.existsSync(instrPath)) {
|
|
412
|
+
rollbackState.originalInstrumentationContent = fs2.readFileSync(instrPath, "utf-8");
|
|
413
|
+
}
|
|
314
414
|
const instrResult = await scaffoldInstrumentation(projectRoot);
|
|
315
415
|
switch (instrResult.action) {
|
|
316
416
|
case "created":
|
|
317
417
|
summary.push("Created instrumentation.ts");
|
|
418
|
+
rollbackState.steps.push("instrumentation");
|
|
318
419
|
break;
|
|
319
420
|
case "injected":
|
|
320
421
|
summary.push("Added registerGlasstrace() to existing instrumentation.ts");
|
|
422
|
+
rollbackState.steps.push("instrumentation");
|
|
321
423
|
break;
|
|
322
424
|
case "already-registered":
|
|
323
425
|
summary.push("Skipped instrumentation.ts (registerGlasstrace already present)");
|
|
@@ -329,6 +431,7 @@ async function runInit(options) {
|
|
|
329
431
|
break;
|
|
330
432
|
}
|
|
331
433
|
} catch (err) {
|
|
434
|
+
await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);
|
|
332
435
|
errors.push(`Failed to write instrumentation.ts: ${err instanceof Error ? err.message : String(err)}`);
|
|
333
436
|
return { exitCode: 1, summary, warnings, errors };
|
|
334
437
|
}
|
|
@@ -336,6 +439,7 @@ async function runInit(options) {
|
|
|
336
439
|
const configResult = await scaffoldNextConfig(projectRoot);
|
|
337
440
|
if (configResult?.modified) {
|
|
338
441
|
summary.push("Wrapped next.config with withGlasstraceConfig()");
|
|
442
|
+
rollbackState.steps.push("next-config");
|
|
339
443
|
} else if (configResult === null) {
|
|
340
444
|
warnings.push("No next.config.* found. You may need to create one for Next.js projects.");
|
|
341
445
|
} else if (configResult.reason === "already-wrapped") {
|
|
@@ -346,6 +450,7 @@ async function runInit(options) {
|
|
|
346
450
|
warnings.push("next.config has no recognizable export pattern \u2014 add withGlasstraceConfig() manually");
|
|
347
451
|
}
|
|
348
452
|
} catch (err) {
|
|
453
|
+
await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);
|
|
349
454
|
errors.push(`Failed to modify next.config: ${err instanceof Error ? err.message : String(err)}`);
|
|
350
455
|
return { exitCode: 1, summary, warnings, errors };
|
|
351
456
|
}
|
|
@@ -353,10 +458,12 @@ async function runInit(options) {
|
|
|
353
458
|
const envCreated = await scaffoldEnvLocal(projectRoot);
|
|
354
459
|
if (envCreated) {
|
|
355
460
|
summary.push("Updated .env.local with Glasstrace configuration");
|
|
461
|
+
rollbackState.steps.push("env-local");
|
|
356
462
|
} else {
|
|
357
463
|
summary.push("Skipped .env.local (GLASSTRACE_API_KEY already configured)");
|
|
358
464
|
}
|
|
359
465
|
} catch (err) {
|
|
466
|
+
await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);
|
|
360
467
|
errors.push(`Failed to update .env.local: ${err instanceof Error ? err.message : String(err)}`);
|
|
361
468
|
return { exitCode: 1, summary, warnings, errors };
|
|
362
469
|
}
|
|
@@ -364,10 +471,12 @@ async function runInit(options) {
|
|
|
364
471
|
const gitignoreUpdated = await scaffoldGitignore(projectRoot);
|
|
365
472
|
if (gitignoreUpdated) {
|
|
366
473
|
summary.push("Updated .gitignore with .glasstrace/");
|
|
474
|
+
rollbackState.steps.push("gitignore");
|
|
367
475
|
} else {
|
|
368
476
|
summary.push("Skipped .gitignore (.glasstrace/ already listed)");
|
|
369
477
|
}
|
|
370
478
|
} catch (err) {
|
|
479
|
+
await rollbackSteps(rollbackState.steps, projectRoot, rollbackState);
|
|
371
480
|
errors.push(`Failed to update .gitignore: ${err instanceof Error ? err.message : String(err)}`);
|
|
372
481
|
return { exitCode: 1, summary, warnings, errors };
|
|
373
482
|
}
|
|
@@ -626,6 +735,7 @@ Usage:
|
|
|
626
735
|
}
|
|
627
736
|
export {
|
|
628
737
|
meetsNodeVersion,
|
|
738
|
+
rollbackSteps,
|
|
629
739
|
runInit
|
|
630
740
|
};
|
|
631
741
|
//# sourceMappingURL=init.js.map
|
package/dist/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/init.ts","../../src/cli/monorepo.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} from \"./scaffolder.js\";\nimport { buildImportGraph } from \"../import-graph.js\";\nimport { getOrCreateAnonKey } 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, formatAgentName } from \"./constants.js\";\nimport { resolveProjectRoot } from \"./monorepo.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\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 * 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 * 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 // Step 2: Ensure instrumentation.ts has registerGlasstrace()\n try {\n const instrResult = await scaffoldInstrumentation(projectRoot);\n switch (instrResult.action) {\n case \"created\":\n summary.push(\"Created instrumentation.ts\");\n break;\n case \"injected\":\n summary.push(\"Added registerGlasstrace() to existing instrumentation.ts\");\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 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 } 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 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 try {\n const envCreated = await scaffoldEnvLocal(projectRoot);\n if (envCreated) {\n summary.push(\"Updated .env.local with Glasstrace configuration\");\n } else {\n summary.push(\"Skipped .env.local (GLASSTRACE_API_KEY already configured)\");\n }\n } catch (err) {\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 } else {\n summary.push(\"Skipped .gitignore (.glasstrace/ already listed)\");\n }\n } catch (err) {\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 const anonKey = await getOrCreateAnonKey(projectRoot);\n let anyConfigWritten = false;\n\n if (isCI) {\n // Non-interactive: write only the generic .glasstrace/mcp.json\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 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 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\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 }\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 };\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 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 } else if (subcommand === \"uninit\") {\n const remainingArgs = process.argv.slice(3);\n const dryRun = remainingArgs.includes(\"--dry-run\");\n\n import(\"./uninit.js\")\n .then(({ runUninit }) => runUninit({ projectRoot: process.cwd(), dryRun }))\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 {\n process.stderr.write(\n `Unknown command: ${subcommand}\\n\\n` +\n \"Usage:\\n\" +\n \" glasstrace init [--yes] [--coverage-map]\\n\" +\n \" glasstrace uninit [--dry-run]\\n\" +\n \" glasstrace mcp add [--force] [--dry-run]\\n\",\n );\n process.exit(1);\n }\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { NEXT_CONFIG_NAMES } from \"./constants.js\";\n\n/** Result of classifying the project root directory. */\nexport interface ProjectClassification {\n /** The directory to scaffold into (may differ from cwd for monorepos). */\n projectRoot: string;\n /** Whether this was auto-resolved from a monorepo root. */\n isMonorepo: boolean;\n /** If monorepo, the relative path from cwd to the resolved app. */\n appRelativePath?: string;\n}\n\n/**\n * Classifies the current directory and resolves the target project root.\n *\n * Classification logic:\n * 1. If the directory contains a Next.js config file, it is a Next.js app\n * directory. Returns it directly.\n * 1b. If no config file exists but package.json lists \"next\" as a dependency,\n * it is still a Next.js app (config files are optional since Next.js 12).\n * 2. If the directory contains monorepo markers (pnpm-workspace.yaml,\n * turbo.json, lerna.json, or a workspaces field in package.json),\n * scans workspace packages for Next.js apps.\n * 3. Otherwise, fails with a user-facing error.\n *\n * @param cwd - The current working directory\n * @returns The resolved project classification\n * @throws Error with a user-facing message if the location is invalid\n */\nexport function resolveProjectRoot(cwd: string): ProjectClassification {\n // Step 1: Check if cwd is a Next.js app directory (config file)\n if (hasNextConfig(cwd)) {\n return { projectRoot: cwd, isMonorepo: false };\n }\n\n // Step 1b: Check if cwd has \"next\" as a dependency (config is optional)\n if (hasNextDependency(cwd)) {\n return { projectRoot: cwd, isMonorepo: false };\n }\n\n // Step 2: Check for monorepo markers\n if (isMonorepoRoot(cwd)) {\n // findNextJsApps throws if no workspace globs are found (e.g., turbo.json\n // exists but no pnpm-workspace.yaml or workspaces in package.json)\n const apps = findNextJsApps(cwd);\n\n if (apps.length === 0) {\n throw new Error(\n \"This is a monorepo but no Next.js apps were found in workspace packages.\",\n );\n }\n\n if (apps.length === 1) {\n const appDir = apps[0];\n const relativePath = path.relative(cwd, appDir);\n return {\n projectRoot: appDir,\n isMonorepo: true,\n appRelativePath: relativePath,\n };\n }\n\n // Multiple apps found — cannot auto-resolve\n const appList = apps\n .map((app) => ` - ${path.relative(cwd, app)}`)\n .join(\"\\n\");\n throw new Error(\n `Found multiple Next.js apps:\\n${appList}\\nRun init from the specific app directory you want to instrument.`,\n );\n }\n\n // Step 3: Neither Next.js app nor monorepo\n throw new Error(\n \"No Next.js project found in the current directory.\\n\" +\n \"Run this command from your Next.js app directory, or from a monorepo root.\",\n );\n}\n\n/**\n * Checks whether the given directory contains a Next.js config file.\n */\nfunction hasNextConfig(dir: string): boolean {\n return NEXT_CONFIG_NAMES.some((name) =>\n fs.existsSync(path.join(dir, name)),\n );\n}\n\n/**\n * Checks whether the given directory's package.json lists \"next\" as a\n * dependency or devDependency. This handles the case where a Next.js app\n * has no explicit config file (config files are optional since Next.js 12).\n */\nfunction hasNextDependency(dir: string): boolean {\n const packageJsonPath = path.join(dir, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n const deps = pkg[\"dependencies\"];\n const devDeps = pkg[\"devDependencies\"];\n\n if (typeof deps === \"object\" && deps !== null && \"next\" in deps) return true;\n if (typeof devDeps === \"object\" && devDeps !== null && \"next\" in devDeps) return true;\n } catch {\n // Invalid JSON — not a Next.js indicator\n }\n\n return false;\n}\n\n/**\n * Detects monorepo markers in the given directory.\n *\n * Checks for:\n * - pnpm-workspace.yaml\n * - turbo.json\n * - lerna.json\n * - \"workspaces\" field in package.json\n */\nexport function isMonorepoRoot(dir: string): boolean {\n // Check for standalone monorepo marker files\n if (fs.existsSync(path.join(dir, \"pnpm-workspace.yaml\"))) return true;\n if (fs.existsSync(path.join(dir, \"turbo.json\"))) return true;\n if (fs.existsSync(path.join(dir, \"lerna.json\"))) return true;\n\n // Check for \"workspaces\" field in package.json\n const packageJsonPath = path.join(dir, \"package.json\");\n if (fs.existsSync(packageJsonPath)) {\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n if (pkg[\"workspaces\"] !== undefined) return true;\n } catch {\n // Invalid JSON — not a monorepo indicator\n }\n }\n\n return false;\n}\n\n/**\n * Finds Next.js apps in workspace packages.\n *\n * Parses workspace globs from:\n * - pnpm-workspace.yaml (packages array)\n * - package.json workspaces field (string[] or { packages: string[] })\n * - lerna.json packages field (string[])\n *\n * Expands the workspace globs using filesystem traversal and returns\n * absolute paths of directories that contain a Next.js config file or\n * have \"next\" as a dependency in package.json.\n *\n * @param monorepoRoot - Absolute path to the monorepo root directory\n * @returns Sorted array of absolute paths to Next.js app directories\n */\nexport function findNextJsApps(monorepoRoot: string): string[] {\n const { includeGlobs, negationPatterns } = collectWorkspaceGlobs(monorepoRoot);\n\n if (includeGlobs.length === 0) {\n throw new Error(\n \"Monorepo detected but no workspace configuration found.\\n\" +\n 'Add a \"workspaces\" field to package.json or create pnpm-workspace.yaml.',\n );\n }\n\n const workspaceDirs = expandGlobs(monorepoRoot, includeGlobs);\n\n // Apply negation patterns: filter out directories matching any exclusion\n const excludedDirs = expandGlobs(monorepoRoot, negationPatterns);\n const excludedSet = new Set(excludedDirs);\n\n // Deduplicate and filter for Next.js apps\n const seen = new Set<string>();\n const nextApps: string[] = [];\n\n for (const dir of workspaceDirs) {\n if (seen.has(dir)) continue;\n seen.add(dir);\n if (excludedSet.has(dir)) continue;\n if (hasNextConfig(dir) || hasNextDependency(dir)) {\n nextApps.push(dir);\n }\n }\n\n return nextApps.sort();\n}\n\n/** Workspace globs split into include and negation patterns. */\nexport interface WorkspaceGlobs {\n includeGlobs: string[];\n negationPatterns: string[];\n}\n\n/**\n * Collects workspace globs from all supported monorepo config sources.\n * Returns deduplicated include globs and negation patterns separately.\n */\nfunction collectWorkspaceGlobs(root: string): WorkspaceGlobs {\n const globs: string[] = [];\n const negations: string[] = [];\n\n // 1. pnpm-workspace.yaml\n const pnpmPath = path.join(root, \"pnpm-workspace.yaml\");\n if (fs.existsSync(pnpmPath)) {\n const content = fs.readFileSync(pnpmPath, \"utf-8\");\n const parsed = parsePnpmWorkspaceYaml(content);\n globs.push(...parsed.includeGlobs);\n negations.push(...parsed.negationPatterns);\n }\n\n // 2. package.json workspaces\n const packageJsonPath = path.join(root, \"package.json\");\n if (fs.existsSync(packageJsonPath)) {\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n globs.push(...parsePackageJsonWorkspaces(pkg));\n } catch {\n // Invalid JSON — skip\n }\n }\n\n // 3. lerna.json packages\n const lernaPath = path.join(root, \"lerna.json\");\n if (fs.existsSync(lernaPath)) {\n try {\n const content = fs.readFileSync(lernaPath, \"utf-8\");\n const lerna = JSON.parse(content) as Record<string, unknown>;\n const packages = lerna[\"packages\"];\n if (Array.isArray(packages)) {\n for (const pkg of packages) {\n if (typeof pkg === \"string\") {\n globs.push(pkg);\n }\n }\n }\n } catch {\n // Invalid JSON — skip\n }\n }\n\n // Deduplicate\n return {\n includeGlobs: [...new Set(globs)],\n negationPatterns: [...new Set(negations)],\n };\n}\n\n/**\n * Parses pnpm-workspace.yaml to extract workspace package globs.\n *\n * The format is simple enough to parse with string processing:\n * ```yaml\n * packages:\n * - \"apps/*\"\n * - packages/*\n * - '!packages/internal'\n * ```\n *\n * Handles both quoted and unquoted values. Negation patterns (lines\n * starting with !) are returned separately so callers can apply them\n * as exclusions after expanding include globs.\n *\n * @internal Exported for unit testing only.\n */\nexport function parsePnpmWorkspaceYaml(content: string): WorkspaceGlobs {\n const lines = content.split(\"\\n\");\n const includeGlobs: string[] = [];\n const negationPatterns: string[] = [];\n let inPackages = false;\n\n for (const rawLine of lines) {\n const trimmed = rawLine.trim();\n\n // Detect the `packages:` key\n if (/^packages\\s*:/.test(trimmed)) {\n inPackages = true;\n continue;\n }\n\n // Stop when we hit another top-level key (no leading whitespace before key)\n if (inPackages && trimmed.length > 0 && !trimmed.startsWith(\"-\") && !rawLine.startsWith(\" \") && !rawLine.startsWith(\"\\t\")) {\n inPackages = false;\n continue;\n }\n\n if (!inPackages) continue;\n\n // Parse list items: ` - \"glob\"` or ` - glob` or ` - 'glob'`\n const itemMatch = /^\\s*-\\s+(.+)$/.exec(rawLine);\n if (!itemMatch) continue;\n\n // Strip surrounding quotes (single or double)\n const value = itemMatch[1].trim().replace(/^[\"']|[\"']$/g, \"\");\n\n // Skip empty values\n if (value.length === 0) continue;\n\n // Collect negation patterns separately (strip the leading !)\n if (value.startsWith(\"!\")) {\n negationPatterns.push(value.slice(1));\n continue;\n }\n\n includeGlobs.push(value);\n }\n\n return { includeGlobs, negationPatterns };\n}\n\n/**\n * Extracts workspace globs from a parsed package.json object.\n *\n * Handles both forms:\n * - `\"workspaces\": [\"packages/*\", \"apps/*\"]`\n * - `\"workspaces\": { \"packages\": [\"packages/*\", \"apps/*\"] }`\n */\nfunction parsePackageJsonWorkspaces(pkg: Record<string, unknown>): string[] {\n const workspaces = pkg[\"workspaces\"];\n if (workspaces === undefined || workspaces === null) return [];\n\n // Array form: string[]\n if (Array.isArray(workspaces)) {\n return workspaces.filter((w): w is string => typeof w === \"string\");\n }\n\n // Object form: { packages: string[] }\n if (typeof workspaces === \"object\") {\n const obj = workspaces as Record<string, unknown>;\n const packages = obj[\"packages\"];\n if (Array.isArray(packages)) {\n return packages.filter((p): p is string => typeof p === \"string\");\n }\n }\n\n return [];\n}\n\n/**\n * Expands workspace globs into actual directory paths.\n *\n * Supports:\n * - `packages/*` — matches one level of directories under packages/\n * - `apps/*` — matches one level of directories under apps/\n * - `packages/foo` — matches a specific directory (literal path)\n * - `packages/**` — recursively walks for directories with package.json\n *\n * @param root - The monorepo root directory\n * @param globs - Workspace glob patterns to expand\n * @returns Array of absolute paths to matched directories\n */\nfunction expandGlobs(root: string, globs: string[]): string[] {\n const dirs: string[] = [];\n\n for (const glob of globs) {\n // Remove trailing slash if present\n const cleanGlob = glob.replace(/\\/+$/, \"\");\n\n if (cleanGlob.includes(\"**\")) {\n // Recursive glob — walk the directory tree\n const prefix = cleanGlob.split(\"**\")[0].replace(/\\/+$/, \"\");\n const baseDir = path.join(root, prefix);\n if (fs.existsSync(baseDir)) {\n dirs.push(...walkDirectories(baseDir));\n }\n } else if (cleanGlob.includes(\"*\")) {\n // Single-level wildcard — expand one directory level\n const parts = cleanGlob.split(\"*\");\n // For \"packages/*\", parts = [\"packages/\", \"\"]\n const baseDir = path.join(root, parts[0].replace(/\\/+$/, \"\"));\n const suffix = parts.slice(1).join(\"*\"); // Anything after the wildcard\n\n if (!fs.existsSync(baseDir)) continue;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(baseDir, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // If there is a suffix pattern, the entry name must end with it\n if (suffix && !entry.name.endsWith(suffix)) continue;\n dirs.push(path.join(baseDir, entry.name));\n }\n } else {\n // Literal path — no wildcards\n const targetDir = path.join(root, cleanGlob);\n if (fs.existsSync(targetDir) && fs.statSync(targetDir).isDirectory()) {\n dirs.push(targetDir);\n }\n }\n }\n\n return dirs;\n}\n\n/**\n * Recursively walks a directory tree and returns all subdirectories\n * that contain a package.json (indicating they are workspace packages).\n * Skips node_modules and hidden directories.\n */\nfunction walkDirectories(baseDir: string): string[] {\n const result: string[] = [];\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(baseDir, { withFileTypes: true });\n } catch {\n return result;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip node_modules and hidden directories\n if (entry.name === \"node_modules\" || entry.name.startsWith(\".\")) continue;\n\n const fullPath = path.join(baseDir, entry.name);\n\n // A workspace package should have a package.json\n if (fs.existsSync(path.join(fullPath, \"package.json\"))) {\n result.push(fullPath);\n }\n\n // Continue recursing for nested workspaces\n result.push(...walkDirectories(fullPath));\n }\n\n return result;\n}\n"],"mappings":"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","names":["fs","path"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/init.ts","../../src/cli/monorepo.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} from \"./scaffolder.js\";\nimport { buildImportGraph } from \"../import-graph.js\";\nimport { getOrCreateAnonKey } 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\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 * 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 try {\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 {\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 const anonKey = await getOrCreateAnonKey(projectRoot);\n let anyConfigWritten = false;\n\n if (isCI) {\n // Non-interactive: write only the generic .glasstrace/mcp.json\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 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 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\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 }\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 };\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 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 } else if (subcommand === \"uninit\") {\n const remainingArgs = process.argv.slice(3);\n const dryRun = remainingArgs.includes(\"--dry-run\");\n\n import(\"./uninit.js\")\n .then(({ runUninit }) => runUninit({ projectRoot: process.cwd(), dryRun }))\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 {\n process.stderr.write(\n `Unknown command: ${subcommand}\\n\\n` +\n \"Usage:\\n\" +\n \" glasstrace init [--yes] [--coverage-map]\\n\" +\n \" glasstrace uninit [--dry-run]\\n\" +\n \" glasstrace mcp add [--force] [--dry-run]\\n\",\n );\n process.exit(1);\n }\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { NEXT_CONFIG_NAMES } from \"./constants.js\";\n\n/** Result of classifying the project root directory. */\nexport interface ProjectClassification {\n /** The directory to scaffold into (may differ from cwd for monorepos). */\n projectRoot: string;\n /** Whether this was auto-resolved from a monorepo root. */\n isMonorepo: boolean;\n /** If monorepo, the relative path from cwd to the resolved app. */\n appRelativePath?: string;\n}\n\n/**\n * Classifies the current directory and resolves the target project root.\n *\n * Classification logic:\n * 1. If the directory contains a Next.js config file, it is a Next.js app\n * directory. Returns it directly.\n * 1b. If no config file exists but package.json lists \"next\" as a dependency,\n * it is still a Next.js app (config files are optional since Next.js 12).\n * 2. If the directory contains monorepo markers (pnpm-workspace.yaml,\n * turbo.json, lerna.json, or a workspaces field in package.json),\n * scans workspace packages for Next.js apps.\n * 3. Otherwise, fails with a user-facing error.\n *\n * @param cwd - The current working directory\n * @returns The resolved project classification\n * @throws Error with a user-facing message if the location is invalid\n */\nexport function resolveProjectRoot(cwd: string): ProjectClassification {\n // Step 1: Check if cwd is a Next.js app directory (config file)\n if (hasNextConfig(cwd)) {\n return { projectRoot: cwd, isMonorepo: false };\n }\n\n // Step 1b: Check if cwd has \"next\" as a dependency (config is optional)\n if (hasNextDependency(cwd)) {\n return { projectRoot: cwd, isMonorepo: false };\n }\n\n // Step 2: Check for monorepo markers\n if (isMonorepoRoot(cwd)) {\n // findNextJsApps throws if no workspace globs are found (e.g., turbo.json\n // exists but no pnpm-workspace.yaml or workspaces in package.json)\n const apps = findNextJsApps(cwd);\n\n if (apps.length === 0) {\n throw new Error(\n \"This is a monorepo but no Next.js apps were found in workspace packages.\",\n );\n }\n\n if (apps.length === 1) {\n const appDir = apps[0];\n const relativePath = path.relative(cwd, appDir);\n return {\n projectRoot: appDir,\n isMonorepo: true,\n appRelativePath: relativePath,\n };\n }\n\n // Multiple apps found — cannot auto-resolve\n const appList = apps\n .map((app) => ` - ${path.relative(cwd, app)}`)\n .join(\"\\n\");\n throw new Error(\n `Found multiple Next.js apps:\\n${appList}\\nRun init from the specific app directory you want to instrument.`,\n );\n }\n\n // Step 3: Neither Next.js app nor monorepo\n throw new Error(\n \"No Next.js project found in the current directory.\\n\" +\n \"Run this command from your Next.js app directory, or from a monorepo root.\",\n );\n}\n\n/**\n * Checks whether the given directory contains a Next.js config file.\n */\nfunction hasNextConfig(dir: string): boolean {\n return NEXT_CONFIG_NAMES.some((name) =>\n fs.existsSync(path.join(dir, name)),\n );\n}\n\n/**\n * Checks whether the given directory's package.json lists \"next\" as a\n * dependency or devDependency. This handles the case where a Next.js app\n * has no explicit config file (config files are optional since Next.js 12).\n */\nfunction hasNextDependency(dir: string): boolean {\n const packageJsonPath = path.join(dir, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n const deps = pkg[\"dependencies\"];\n const devDeps = pkg[\"devDependencies\"];\n\n if (typeof deps === \"object\" && deps !== null && \"next\" in deps) return true;\n if (typeof devDeps === \"object\" && devDeps !== null && \"next\" in devDeps) return true;\n } catch {\n // Invalid JSON — not a Next.js indicator\n }\n\n return false;\n}\n\n/**\n * Detects monorepo markers in the given directory.\n *\n * Checks for:\n * - pnpm-workspace.yaml\n * - turbo.json\n * - lerna.json\n * - \"workspaces\" field in package.json\n */\nexport function isMonorepoRoot(dir: string): boolean {\n // Check for standalone monorepo marker files\n if (fs.existsSync(path.join(dir, \"pnpm-workspace.yaml\"))) return true;\n if (fs.existsSync(path.join(dir, \"turbo.json\"))) return true;\n if (fs.existsSync(path.join(dir, \"lerna.json\"))) return true;\n\n // Check for \"workspaces\" field in package.json\n const packageJsonPath = path.join(dir, \"package.json\");\n if (fs.existsSync(packageJsonPath)) {\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n if (pkg[\"workspaces\"] !== undefined) return true;\n } catch {\n // Invalid JSON — not a monorepo indicator\n }\n }\n\n return false;\n}\n\n/**\n * Finds Next.js apps in workspace packages.\n *\n * Parses workspace globs from:\n * - pnpm-workspace.yaml (packages array)\n * - package.json workspaces field (string[] or { packages: string[] })\n * - lerna.json packages field (string[])\n *\n * Expands the workspace globs using filesystem traversal and returns\n * absolute paths of directories that contain a Next.js config file or\n * have \"next\" as a dependency in package.json.\n *\n * @param monorepoRoot - Absolute path to the monorepo root directory\n * @returns Sorted array of absolute paths to Next.js app directories\n */\nexport function findNextJsApps(monorepoRoot: string): string[] {\n const { includeGlobs, negationPatterns } = collectWorkspaceGlobs(monorepoRoot);\n\n if (includeGlobs.length === 0) {\n throw new Error(\n \"Monorepo detected but no workspace configuration found.\\n\" +\n 'Add a \"workspaces\" field to package.json or create pnpm-workspace.yaml.',\n );\n }\n\n const workspaceDirs = expandGlobs(monorepoRoot, includeGlobs);\n\n // Apply negation patterns: filter out directories matching any exclusion\n const excludedDirs = expandGlobs(monorepoRoot, negationPatterns);\n const excludedSet = new Set(excludedDirs);\n\n // Deduplicate and filter for Next.js apps\n const seen = new Set<string>();\n const nextApps: string[] = [];\n\n for (const dir of workspaceDirs) {\n if (seen.has(dir)) continue;\n seen.add(dir);\n if (excludedSet.has(dir)) continue;\n if (hasNextConfig(dir) || hasNextDependency(dir)) {\n nextApps.push(dir);\n }\n }\n\n return nextApps.sort();\n}\n\n/** Workspace globs split into include and negation patterns. */\nexport interface WorkspaceGlobs {\n includeGlobs: string[];\n negationPatterns: string[];\n}\n\n/**\n * Collects workspace globs from all supported monorepo config sources.\n * Returns deduplicated include globs and negation patterns separately.\n */\nfunction collectWorkspaceGlobs(root: string): WorkspaceGlobs {\n const globs: string[] = [];\n const negations: string[] = [];\n\n // 1. pnpm-workspace.yaml\n const pnpmPath = path.join(root, \"pnpm-workspace.yaml\");\n if (fs.existsSync(pnpmPath)) {\n const content = fs.readFileSync(pnpmPath, \"utf-8\");\n const parsed = parsePnpmWorkspaceYaml(content);\n globs.push(...parsed.includeGlobs);\n negations.push(...parsed.negationPatterns);\n }\n\n // 2. package.json workspaces\n const packageJsonPath = path.join(root, \"package.json\");\n if (fs.existsSync(packageJsonPath)) {\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as Record<string, unknown>;\n globs.push(...parsePackageJsonWorkspaces(pkg));\n } catch {\n // Invalid JSON — skip\n }\n }\n\n // 3. lerna.json packages\n const lernaPath = path.join(root, \"lerna.json\");\n if (fs.existsSync(lernaPath)) {\n try {\n const content = fs.readFileSync(lernaPath, \"utf-8\");\n const lerna = JSON.parse(content) as Record<string, unknown>;\n const packages = lerna[\"packages\"];\n if (Array.isArray(packages)) {\n for (const pkg of packages) {\n if (typeof pkg === \"string\") {\n globs.push(pkg);\n }\n }\n }\n } catch {\n // Invalid JSON — skip\n }\n }\n\n // Deduplicate\n return {\n includeGlobs: [...new Set(globs)],\n negationPatterns: [...new Set(negations)],\n };\n}\n\n/**\n * Parses pnpm-workspace.yaml to extract workspace package globs.\n *\n * The format is simple enough to parse with string processing:\n * ```yaml\n * packages:\n * - \"apps/*\"\n * - packages/*\n * - '!packages/internal'\n * ```\n *\n * Handles both quoted and unquoted values. Negation patterns (lines\n * starting with !) are returned separately so callers can apply them\n * as exclusions after expanding include globs.\n *\n * @internal Exported for unit testing only.\n */\nexport function parsePnpmWorkspaceYaml(content: string): WorkspaceGlobs {\n const lines = content.split(\"\\n\");\n const includeGlobs: string[] = [];\n const negationPatterns: string[] = [];\n let inPackages = false;\n\n for (const rawLine of lines) {\n const trimmed = rawLine.trim();\n\n // Detect the `packages:` key\n if (/^packages\\s*:/.test(trimmed)) {\n inPackages = true;\n continue;\n }\n\n // Stop when we hit another top-level key (no leading whitespace before key)\n if (inPackages && trimmed.length > 0 && !trimmed.startsWith(\"-\") && !rawLine.startsWith(\" \") && !rawLine.startsWith(\"\\t\")) {\n inPackages = false;\n continue;\n }\n\n if (!inPackages) continue;\n\n // Parse list items: ` - \"glob\"` or ` - glob` or ` - 'glob'`\n const itemMatch = /^\\s*-\\s+(.+)$/.exec(rawLine);\n if (!itemMatch) continue;\n\n // Strip surrounding quotes (single or double)\n const value = itemMatch[1].trim().replace(/^[\"']|[\"']$/g, \"\");\n\n // Skip empty values\n if (value.length === 0) continue;\n\n // Collect negation patterns separately (strip the leading !)\n if (value.startsWith(\"!\")) {\n negationPatterns.push(value.slice(1));\n continue;\n }\n\n includeGlobs.push(value);\n }\n\n return { includeGlobs, negationPatterns };\n}\n\n/**\n * Extracts workspace globs from a parsed package.json object.\n *\n * Handles both forms:\n * - `\"workspaces\": [\"packages/*\", \"apps/*\"]`\n * - `\"workspaces\": { \"packages\": [\"packages/*\", \"apps/*\"] }`\n */\nfunction parsePackageJsonWorkspaces(pkg: Record<string, unknown>): string[] {\n const workspaces = pkg[\"workspaces\"];\n if (workspaces === undefined || workspaces === null) return [];\n\n // Array form: string[]\n if (Array.isArray(workspaces)) {\n return workspaces.filter((w): w is string => typeof w === \"string\");\n }\n\n // Object form: { packages: string[] }\n if (typeof workspaces === \"object\") {\n const obj = workspaces as Record<string, unknown>;\n const packages = obj[\"packages\"];\n if (Array.isArray(packages)) {\n return packages.filter((p): p is string => typeof p === \"string\");\n }\n }\n\n return [];\n}\n\n/**\n * Expands workspace globs into actual directory paths.\n *\n * Supports:\n * - `packages/*` — matches one level of directories under packages/\n * - `apps/*` — matches one level of directories under apps/\n * - `packages/foo` — matches a specific directory (literal path)\n * - `packages/**` — recursively walks for directories with package.json\n *\n * @param root - The monorepo root directory\n * @param globs - Workspace glob patterns to expand\n * @returns Array of absolute paths to matched directories\n */\nfunction expandGlobs(root: string, globs: string[]): string[] {\n const dirs: string[] = [];\n\n for (const glob of globs) {\n // Remove trailing slash if present\n const cleanGlob = glob.replace(/\\/+$/, \"\");\n\n if (cleanGlob.includes(\"**\")) {\n // Recursive glob — walk the directory tree\n const prefix = cleanGlob.split(\"**\")[0].replace(/\\/+$/, \"\");\n const baseDir = path.join(root, prefix);\n if (fs.existsSync(baseDir)) {\n dirs.push(...walkDirectories(baseDir));\n }\n } else if (cleanGlob.includes(\"*\")) {\n // Single-level wildcard — expand one directory level\n const parts = cleanGlob.split(\"*\");\n // For \"packages/*\", parts = [\"packages/\", \"\"]\n const baseDir = path.join(root, parts[0].replace(/\\/+$/, \"\"));\n const suffix = parts.slice(1).join(\"*\"); // Anything after the wildcard\n\n if (!fs.existsSync(baseDir)) continue;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(baseDir, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // If there is a suffix pattern, the entry name must end with it\n if (suffix && !entry.name.endsWith(suffix)) continue;\n dirs.push(path.join(baseDir, entry.name));\n }\n } else {\n // Literal path — no wildcards\n const targetDir = path.join(root, cleanGlob);\n if (fs.existsSync(targetDir) && fs.statSync(targetDir).isDirectory()) {\n dirs.push(targetDir);\n }\n }\n }\n\n return dirs;\n}\n\n/**\n * Recursively walks a directory tree and returns all subdirectories\n * that contain a package.json (indicating they are workspace packages).\n * Skips node_modules and hidden directories.\n */\nfunction walkDirectories(baseDir: string): string[] {\n const result: string[] = [];\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(baseDir, { withFileTypes: true });\n } catch {\n return result;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n // Skip node_modules and hidden directories\n if (entry.name === \"node_modules\" || entry.name.startsWith(\".\")) continue;\n\n const fullPath = path.join(baseDir, entry.name);\n\n // A workspace package should have a package.json\n if (fs.existsSync(path.join(fullPath, \"package.json\"))) {\n result.push(fullPath);\n }\n\n // Continue recursing for nested workspaces\n result.push(...walkDirectories(fullPath));\n }\n\n return result;\n}\n"],"mappings":"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","names":["fs","path"]}
|