@glasstrace/sdk 0.12.4 → 0.13.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/cli/init.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ resolveProjectRoot
4
+ } from "../chunk-RFSCWIVN.js";
2
5
  import {
3
6
  buildImportGraph
4
7
  } from "../chunk-LW7DPKBA.js";
@@ -35,242 +38,9 @@ import {
35
38
  import "../chunk-NSBPE2FW.js";
36
39
 
37
40
  // src/cli/init.ts
38
- import * as fs2 from "fs";
39
- import * as path2 from "path";
40
- import * as readline from "readline";
41
-
42
- // src/cli/monorepo.ts
43
41
  import * as fs from "fs";
44
42
  import * as path from "path";
45
- function resolveProjectRoot(cwd) {
46
- if (hasNextConfig(cwd)) {
47
- return { projectRoot: cwd, isMonorepo: false };
48
- }
49
- if (hasNextDependency(cwd)) {
50
- return { projectRoot: cwd, isMonorepo: false };
51
- }
52
- if (isMonorepoRoot(cwd)) {
53
- const apps = findNextJsApps(cwd);
54
- if (apps.length === 0) {
55
- throw new Error(
56
- "This is a monorepo but no Next.js apps were found in workspace packages."
57
- );
58
- }
59
- if (apps.length === 1) {
60
- const appDir = apps[0];
61
- const relativePath = path.relative(cwd, appDir);
62
- return {
63
- projectRoot: appDir,
64
- isMonorepo: true,
65
- appRelativePath: relativePath
66
- };
67
- }
68
- const appList = apps.map((app) => ` - ${path.relative(cwd, app)}`).join("\n");
69
- throw new Error(
70
- `Found multiple Next.js apps:
71
- ${appList}
72
- Run init from the specific app directory you want to instrument.`
73
- );
74
- }
75
- throw new Error(
76
- "No Next.js project found in the current directory.\nRun this command from your Next.js app directory, or from a monorepo root."
77
- );
78
- }
79
- function hasNextConfig(dir) {
80
- return NEXT_CONFIG_NAMES.some(
81
- (name) => fs.existsSync(path.join(dir, name))
82
- );
83
- }
84
- function hasNextDependency(dir) {
85
- const packageJsonPath = path.join(dir, "package.json");
86
- if (!fs.existsSync(packageJsonPath)) return false;
87
- try {
88
- const content = fs.readFileSync(packageJsonPath, "utf-8");
89
- const pkg = JSON.parse(content);
90
- const deps = pkg["dependencies"];
91
- const devDeps = pkg["devDependencies"];
92
- if (typeof deps === "object" && deps !== null && "next" in deps) return true;
93
- if (typeof devDeps === "object" && devDeps !== null && "next" in devDeps) return true;
94
- } catch {
95
- }
96
- return false;
97
- }
98
- function isMonorepoRoot(dir) {
99
- if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return true;
100
- if (fs.existsSync(path.join(dir, "turbo.json"))) return true;
101
- if (fs.existsSync(path.join(dir, "lerna.json"))) return true;
102
- const packageJsonPath = path.join(dir, "package.json");
103
- if (fs.existsSync(packageJsonPath)) {
104
- try {
105
- const content = fs.readFileSync(packageJsonPath, "utf-8");
106
- const pkg = JSON.parse(content);
107
- if (pkg["workspaces"] !== void 0) return true;
108
- } catch {
109
- }
110
- }
111
- return false;
112
- }
113
- function findNextJsApps(monorepoRoot) {
114
- const { includeGlobs, negationPatterns } = collectWorkspaceGlobs(monorepoRoot);
115
- if (includeGlobs.length === 0) {
116
- throw new Error(
117
- 'Monorepo detected but no workspace configuration found.\nAdd a "workspaces" field to package.json or create pnpm-workspace.yaml.'
118
- );
119
- }
120
- const workspaceDirs = expandGlobs(monorepoRoot, includeGlobs);
121
- const excludedDirs = expandGlobs(monorepoRoot, negationPatterns);
122
- const excludedSet = new Set(excludedDirs);
123
- const seen = /* @__PURE__ */ new Set();
124
- const nextApps = [];
125
- for (const dir of workspaceDirs) {
126
- if (seen.has(dir)) continue;
127
- seen.add(dir);
128
- if (excludedSet.has(dir)) continue;
129
- if (hasNextConfig(dir) || hasNextDependency(dir)) {
130
- nextApps.push(dir);
131
- }
132
- }
133
- return nextApps.sort();
134
- }
135
- function collectWorkspaceGlobs(root) {
136
- const globs = [];
137
- const negations = [];
138
- const pnpmPath = path.join(root, "pnpm-workspace.yaml");
139
- if (fs.existsSync(pnpmPath)) {
140
- const content = fs.readFileSync(pnpmPath, "utf-8");
141
- const parsed = parsePnpmWorkspaceYaml(content);
142
- globs.push(...parsed.includeGlobs);
143
- negations.push(...parsed.negationPatterns);
144
- }
145
- const packageJsonPath = path.join(root, "package.json");
146
- if (fs.existsSync(packageJsonPath)) {
147
- try {
148
- const content = fs.readFileSync(packageJsonPath, "utf-8");
149
- const pkg = JSON.parse(content);
150
- globs.push(...parsePackageJsonWorkspaces(pkg));
151
- } catch {
152
- }
153
- }
154
- const lernaPath = path.join(root, "lerna.json");
155
- if (fs.existsSync(lernaPath)) {
156
- try {
157
- const content = fs.readFileSync(lernaPath, "utf-8");
158
- const lerna = JSON.parse(content);
159
- const packages = lerna["packages"];
160
- if (Array.isArray(packages)) {
161
- for (const pkg of packages) {
162
- if (typeof pkg === "string") {
163
- globs.push(pkg);
164
- }
165
- }
166
- }
167
- } catch {
168
- }
169
- }
170
- return {
171
- includeGlobs: [...new Set(globs)],
172
- negationPatterns: [...new Set(negations)]
173
- };
174
- }
175
- function parsePnpmWorkspaceYaml(content) {
176
- const lines = content.split("\n");
177
- const includeGlobs = [];
178
- const negationPatterns = [];
179
- let inPackages = false;
180
- for (const rawLine of lines) {
181
- const trimmed = rawLine.trim();
182
- if (/^packages\s*:/.test(trimmed)) {
183
- inPackages = true;
184
- continue;
185
- }
186
- if (inPackages && trimmed.length > 0 && !trimmed.startsWith("-") && !rawLine.startsWith(" ") && !rawLine.startsWith(" ")) {
187
- inPackages = false;
188
- continue;
189
- }
190
- if (!inPackages) continue;
191
- const itemMatch = /^\s*-\s+(.+)$/.exec(rawLine);
192
- if (!itemMatch) continue;
193
- const value = itemMatch[1].trim().replace(/^["']|["']$/g, "");
194
- if (value.length === 0) continue;
195
- if (value.startsWith("!")) {
196
- negationPatterns.push(value.slice(1));
197
- continue;
198
- }
199
- includeGlobs.push(value);
200
- }
201
- return { includeGlobs, negationPatterns };
202
- }
203
- function parsePackageJsonWorkspaces(pkg) {
204
- const workspaces = pkg["workspaces"];
205
- if (workspaces === void 0 || workspaces === null) return [];
206
- if (Array.isArray(workspaces)) {
207
- return workspaces.filter((w) => typeof w === "string");
208
- }
209
- if (typeof workspaces === "object") {
210
- const obj = workspaces;
211
- const packages = obj["packages"];
212
- if (Array.isArray(packages)) {
213
- return packages.filter((p) => typeof p === "string");
214
- }
215
- }
216
- return [];
217
- }
218
- function expandGlobs(root, globs) {
219
- const dirs = [];
220
- for (const glob of globs) {
221
- const cleanGlob = glob.replace(/\/+$/, "");
222
- if (cleanGlob.includes("**")) {
223
- const prefix = cleanGlob.split("**")[0].replace(/\/+$/, "");
224
- const baseDir = path.join(root, prefix);
225
- if (fs.existsSync(baseDir)) {
226
- dirs.push(...walkDirectories(baseDir));
227
- }
228
- } else if (cleanGlob.includes("*")) {
229
- const parts = cleanGlob.split("*");
230
- const baseDir = path.join(root, parts[0].replace(/\/+$/, ""));
231
- const suffix = parts.slice(1).join("*");
232
- if (!fs.existsSync(baseDir)) continue;
233
- let entries;
234
- try {
235
- entries = fs.readdirSync(baseDir, { withFileTypes: true });
236
- } catch {
237
- continue;
238
- }
239
- for (const entry of entries) {
240
- if (!entry.isDirectory()) continue;
241
- if (suffix && !entry.name.endsWith(suffix)) continue;
242
- dirs.push(path.join(baseDir, entry.name));
243
- }
244
- } else {
245
- const targetDir = path.join(root, cleanGlob);
246
- if (fs.existsSync(targetDir) && fs.statSync(targetDir).isDirectory()) {
247
- dirs.push(targetDir);
248
- }
249
- }
250
- }
251
- return dirs;
252
- }
253
- function walkDirectories(baseDir) {
254
- const result = [];
255
- let entries;
256
- try {
257
- entries = fs.readdirSync(baseDir, { withFileTypes: true });
258
- } catch {
259
- return result;
260
- }
261
- for (const entry of entries) {
262
- if (!entry.isDirectory()) continue;
263
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
264
- const fullPath = path.join(baseDir, entry.name);
265
- if (fs.existsSync(path.join(fullPath, "package.json"))) {
266
- result.push(fullPath);
267
- }
268
- result.push(...walkDirectories(fullPath));
269
- }
270
- return result;
271
- }
272
-
273
- // src/cli/init.ts
43
+ import * as readline from "readline";
274
44
  function meetsNodeVersion(minMajor) {
275
45
  const [major] = process.versions.node.split(".").map(Number);
276
46
  return major >= minMajor;
@@ -304,17 +74,17 @@ async function rollbackSteps(steps, projectRoot, state) {
304
74
  try {
305
75
  switch (step) {
306
76
  case "instrumentation": {
307
- const instrPath = path2.join(projectRoot, "instrumentation.ts");
308
- if (fs2.existsSync(instrPath)) {
309
- const content = fs2.readFileSync(instrPath, "utf-8");
77
+ const instrPath = path.join(projectRoot, "instrumentation.ts");
78
+ if (fs.existsSync(instrPath)) {
79
+ const content = fs.readFileSync(instrPath, "utf-8");
310
80
  if (isInitCreatedInstrumentation(content)) {
311
- fs2.unlinkSync(instrPath);
81
+ fs.unlinkSync(instrPath);
312
82
  } else if (state?.originalInstrumentationContent !== void 0) {
313
- fs2.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
83
+ fs.writeFileSync(instrPath, state.originalInstrumentationContent, "utf-8");
314
84
  } else {
315
85
  const cleaned = removeRegisterGlasstrace(content);
316
86
  if (cleaned !== content) {
317
- fs2.writeFileSync(instrPath, cleaned, "utf-8");
87
+ fs.writeFileSync(instrPath, cleaned, "utf-8");
318
88
  }
319
89
  }
320
90
  }
@@ -322,11 +92,11 @@ async function rollbackSteps(steps, projectRoot, state) {
322
92
  }
323
93
  case "next-config": {
324
94
  for (const name of NEXT_CONFIG_NAMES) {
325
- const configPath = path2.join(projectRoot, name);
326
- if (!fs2.existsSync(configPath)) {
95
+ const configPath = path.join(projectRoot, name);
96
+ if (!fs.existsSync(configPath)) {
327
97
  continue;
328
98
  }
329
- const content = fs2.readFileSync(configPath, "utf-8");
99
+ const content = fs.readFileSync(configPath, "utf-8");
330
100
  if (!content.includes("withGlasstraceConfig")) {
331
101
  continue;
332
102
  }
@@ -334,16 +104,16 @@ async function rollbackSteps(steps, projectRoot, state) {
334
104
  const unwrapResult = isESM ? unwrapExport(content) : unwrapCJSExport(content);
335
105
  if (unwrapResult.unwrapped) {
336
106
  const cleaned = removeGlasstraceConfigImport(unwrapResult.content);
337
- fs2.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), "utf-8");
107
+ fs.writeFileSync(configPath, cleanLeadingBlankLines(cleaned), "utf-8");
338
108
  }
339
109
  break;
340
110
  }
341
111
  break;
342
112
  }
343
113
  case "env-local": {
344
- const envPath = path2.join(projectRoot, ".env.local");
345
- if (fs2.existsSync(envPath)) {
346
- const content = fs2.readFileSync(envPath, "utf-8");
114
+ const envPath = path.join(projectRoot, ".env.local");
115
+ if (fs.existsSync(envPath)) {
116
+ const content = fs.readFileSync(envPath, "utf-8");
347
117
  const lines = content.split("\n");
348
118
  const filtered = lines.filter((line) => {
349
119
  const trimmed = line.trim();
@@ -352,18 +122,18 @@ async function rollbackSteps(steps, projectRoot, state) {
352
122
  if (filtered.length !== lines.length) {
353
123
  const result = filtered.join("\n");
354
124
  if (result.trim().length === 0) {
355
- fs2.unlinkSync(envPath);
125
+ fs.unlinkSync(envPath);
356
126
  } else {
357
- fs2.writeFileSync(envPath, result, "utf-8");
127
+ fs.writeFileSync(envPath, result, "utf-8");
358
128
  }
359
129
  }
360
130
  }
361
131
  break;
362
132
  }
363
133
  case "gitignore": {
364
- const gitignorePath = path2.join(projectRoot, ".gitignore");
365
- if (fs2.existsSync(gitignorePath)) {
366
- const content = fs2.readFileSync(gitignorePath, "utf-8");
134
+ const gitignorePath = path.join(projectRoot, ".gitignore");
135
+ if (fs.existsSync(gitignorePath)) {
136
+ const content = fs.readFileSync(gitignorePath, "utf-8");
367
137
  const lines = content.split("\n");
368
138
  const filtered = lines.filter(
369
139
  (line) => line.trim() !== ".glasstrace/"
@@ -371,9 +141,9 @@ async function rollbackSteps(steps, projectRoot, state) {
371
141
  if (filtered.length !== lines.length) {
372
142
  const result = filtered.join("\n");
373
143
  if (result.trim().length === 0) {
374
- fs2.unlinkSync(gitignorePath);
144
+ fs.unlinkSync(gitignorePath);
375
145
  } else {
376
- fs2.writeFileSync(gitignorePath, result, "utf-8");
146
+ fs.writeFileSync(gitignorePath, result, "utf-8");
377
147
  }
378
148
  }
379
149
  }
@@ -400,16 +170,16 @@ async function runInit(options) {
400
170
  errors.push(err instanceof Error ? err.message : String(err));
401
171
  return { exitCode: 1, summary, warnings, errors };
402
172
  }
403
- const packageJsonPath = path2.join(projectRoot, "package.json");
404
- if (!fs2.existsSync(packageJsonPath)) {
173
+ const packageJsonPath = path.join(projectRoot, "package.json");
174
+ if (!fs.existsSync(packageJsonPath)) {
405
175
  errors.push("No package.json found. Run this command from a Node.js project root.");
406
176
  return { exitCode: 1, summary, warnings, errors };
407
177
  }
408
178
  const rollbackState = { steps: [] };
409
179
  try {
410
- const instrPath = path2.join(projectRoot, "instrumentation.ts");
411
- if (fs2.existsSync(instrPath)) {
412
- rollbackState.originalInstrumentationContent = fs2.readFileSync(instrPath, "utf-8");
180
+ const instrPath = path.join(projectRoot, "instrumentation.ts");
181
+ if (fs.existsSync(instrPath)) {
182
+ rollbackState.originalInstrumentationContent = fs.readFileSync(instrPath, "utf-8");
413
183
  }
414
184
  const instrResult = await scaffoldInstrumentation(projectRoot);
415
185
  switch (instrResult.action) {
@@ -488,14 +258,14 @@ async function runInit(options) {
488
258
  if (isCI) {
489
259
  const genericAgent = {
490
260
  name: "generic",
491
- mcpConfigPath: path2.join(projectRoot, ".glasstrace", "mcp.json"),
261
+ mcpConfigPath: path.join(projectRoot, ".glasstrace", "mcp.json"),
492
262
  infoFilePath: null,
493
263
  cliAvailable: false,
494
264
  registrationCommand: null
495
265
  };
496
266
  const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
497
267
  await writeMcpConfig(genericAgent, genericConfig, projectRoot);
498
- if (genericAgent.mcpConfigPath !== null && fs2.existsSync(genericAgent.mcpConfigPath)) {
268
+ if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {
499
269
  anyConfigWritten = true;
500
270
  summary.push("Created .glasstrace/mcp.json (CI mode)");
501
271
  }
@@ -509,14 +279,14 @@ async function runInit(options) {
509
279
  );
510
280
  const genericAgent = {
511
281
  name: "generic",
512
- mcpConfigPath: path2.join(projectRoot, ".glasstrace", "mcp.json"),
282
+ mcpConfigPath: path.join(projectRoot, ".glasstrace", "mcp.json"),
513
283
  infoFilePath: null,
514
284
  cliAvailable: false,
515
285
  registrationCommand: null
516
286
  };
517
287
  const genericConfig = generateMcpConfig(genericAgent, MCP_ENDPOINT, anonKey);
518
288
  await writeMcpConfig(genericAgent, genericConfig, projectRoot);
519
- if (genericAgent.mcpConfigPath !== null && fs2.existsSync(genericAgent.mcpConfigPath)) {
289
+ if (genericAgent.mcpConfigPath !== null && fs.existsSync(genericAgent.mcpConfigPath)) {
520
290
  anyConfigWritten = true;
521
291
  }
522
292
  agents = [];
@@ -526,7 +296,7 @@ async function runInit(options) {
526
296
  try {
527
297
  const configContent = generateMcpConfig(agent, MCP_ENDPOINT, anonKey);
528
298
  await writeMcpConfig(agent, configContent, projectRoot);
529
- const configExists = agent.mcpConfigPath !== null && fs2.existsSync(agent.mcpConfigPath);
299
+ const configExists = agent.mcpConfigPath !== null && fs.existsSync(agent.mcpConfigPath);
530
300
  if (!configExists) {
531
301
  continue;
532
302
  }
@@ -613,7 +383,7 @@ function parseArgs(argv) {
613
383
  };
614
384
  }
615
385
  var scriptPath = typeof process !== "undefined" && process.argv[1] !== void 0 ? process.argv[1].replace(/\\/g, "/") : void 0;
616
- var scriptBasename = scriptPath !== void 0 ? path2.basename(scriptPath) : void 0;
386
+ var scriptBasename = scriptPath !== void 0 ? path.basename(scriptPath) : void 0;
617
387
  var isDirectExecution = scriptPath !== void 0 && (scriptPath.endsWith("/cli/init.js") || scriptPath.endsWith("/cli/init.ts") || scriptBasename === "glasstrace");
618
388
  if (isDirectExecution) {
619
389
  if (!meetsNodeVersion(20)) {
@@ -716,6 +486,46 @@ Usage: glasstrace mcp add [--force] [--dry-run]
716
486
  }).catch((err) => {
717
487
  process.stderr.write(
718
488
  `Fatal error: ${err instanceof Error ? err.message : String(err)}
489
+ `
490
+ );
491
+ process.exit(1);
492
+ });
493
+ } else if (subcommand === "status") {
494
+ const remainingArgs = process.argv.slice(3);
495
+ const json = remainingArgs.includes("--json");
496
+ Promise.all([import("./status.js"), import("../monorepo-7SBKH7RP.js")]).then(([{ runStatus }, { resolveProjectRoot: resolve }]) => {
497
+ let projectRoot = process.cwd();
498
+ try {
499
+ projectRoot = resolve(projectRoot).projectRoot;
500
+ } catch {
501
+ }
502
+ const result = runStatus({ projectRoot });
503
+ if (json) {
504
+ process.stdout.write(JSON.stringify(result) + "\n");
505
+ } else {
506
+ const checks = [
507
+ ["Installed", result.installed],
508
+ ["Initialized", result.initialized],
509
+ ["Instrumentation", result.instrumentation],
510
+ ["Config wrapped", result.configWrapped],
511
+ ["Anon key", result.anonKey],
512
+ ["MCP configured", result.mcpConfigured]
513
+ ];
514
+ for (const [label, ok] of checks) {
515
+ process.stderr.write(` ${ok ? "+" : "-"} ${label}
516
+ `);
517
+ }
518
+ if (result.agents.length > 0) {
519
+ process.stderr.write(` + Agents: ${result.agents.join(", ")}
520
+ `);
521
+ } else {
522
+ process.stderr.write(" - Agents\n");
523
+ }
524
+ }
525
+ process.exit(0);
526
+ }).catch((err) => {
527
+ process.stderr.write(
528
+ `Fatal error: ${err instanceof Error ? err.message : String(err)}
719
529
  `
720
530
  );
721
531
  process.exit(1);
@@ -727,6 +537,7 @@ Usage: glasstrace mcp add [--force] [--dry-run]
727
537
  Usage:
728
538
  glasstrace init [--yes] [--coverage-map]
729
539
  glasstrace uninit [--dry-run]
540
+ glasstrace status [--json]
730
541
  glasstrace mcp add [--force] [--dry-run]
731
542
  `
732
543
  );