@glasstrace/sdk 1.5.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -0
- package/dist/{chunk-YLY7AGLC.js → chunk-3PJP5Y3U.js} +3 -3
- package/dist/{chunk-Q42BY5BA.js → chunk-H57MQGNU.js} +2 -2
- package/dist/{chunk-D3QXU2VM.js → chunk-KI7YJ7XD.js} +2 -2
- package/dist/{chunk-D3QXU2VM.js.map → chunk-KI7YJ7XD.js.map} +1 -1
- package/dist/{chunk-TANUWTFO.js → chunk-M2TLX6NM.js} +3 -3
- package/dist/{chunk-MMKFFF2L.js → chunk-NN5YCETI.js} +2 -2
- package/dist/{chunk-4WI7B5FQ.js → chunk-P45NZR4J.js} +21 -1
- package/dist/chunk-P45NZR4J.js.map +1 -0
- package/dist/{chunk-MLRQTCCK.js → chunk-SYNQJZZY.js} +205 -28
- package/dist/chunk-SYNQJZZY.js.map +1 -0
- package/dist/{chunk-QU26IKIJ.js → chunk-UQKI476D.js} +2 -2
- package/dist/{chunk-MFYOQOD7.js → chunk-WL6BXEJ5.js} +2 -2
- package/dist/cli/init.cjs +5 -5
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +8 -8
- package/dist/cli/mcp-add.cjs +2 -2
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +4 -4
- package/dist/cli/uninit.js +3 -3
- package/dist/cli/upgrade-instructions.cjs +2 -2
- package/dist/cli/upgrade-instructions.cjs.map +1 -1
- package/dist/cli/upgrade-instructions.js +4 -4
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.js +2 -2
- package/dist/edge-entry.cjs +20 -0
- package/dist/edge-entry.cjs.map +1 -1
- package/dist/edge-entry.js +2 -2
- package/dist/index.cjs +220 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/dist/node-entry.cjs +220 -23
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +7 -7
- package/dist/node-subpath.cjs.map +1 -1
- package/dist/node-subpath.js +3 -3
- package/dist/{source-map-uploader-PB3M4PPP.js → source-map-uploader-XFUEVV7I.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-4WI7B5FQ.js.map +0 -1
- package/dist/chunk-MLRQTCCK.js.map +0 -1
- /package/dist/{chunk-YLY7AGLC.js.map → chunk-3PJP5Y3U.js.map} +0 -0
- /package/dist/{chunk-Q42BY5BA.js.map → chunk-H57MQGNU.js.map} +0 -0
- /package/dist/{chunk-TANUWTFO.js.map → chunk-M2TLX6NM.js.map} +0 -0
- /package/dist/{chunk-MMKFFF2L.js.map → chunk-NN5YCETI.js.map} +0 -0
- /package/dist/{chunk-QU26IKIJ.js.map → chunk-UQKI476D.js.map} +0 -0
- /package/dist/{chunk-MFYOQOD7.js.map → chunk-WL6BXEJ5.js.map} +0 -0
- /package/dist/{source-map-uploader-PB3M4PPP.js.map → source-map-uploader-XFUEVV7I.js.map} +0 -0
package/README.md
CHANGED
|
@@ -349,6 +349,114 @@ body data. If your account enables the flag but a span never carries
|
|
|
349
349
|
the internal attribute (no adapter set it), the public attribute is
|
|
350
350
|
still absent. The default is "off, twice".
|
|
351
351
|
|
|
352
|
+
## Capturing error evidence
|
|
353
|
+
|
|
354
|
+
For server-side errors, the SDK promotes a curated set of OTel
|
|
355
|
+
attributes into the `glasstrace.error.*` family so product
|
|
356
|
+
consumers can render bounded, sanitized error evidence without
|
|
357
|
+
having to parse raw stack traces or framework HTML themselves.
|
|
358
|
+
|
|
359
|
+
### Bounded stack capture
|
|
360
|
+
|
|
361
|
+
When an OTel `recordException()` event (or a span attribute carrying
|
|
362
|
+
`exception.stacktrace`) is observed on a failed span, the SDK
|
|
363
|
+
emits the stack as `glasstrace.error.stack` with two sibling
|
|
364
|
+
booleans:
|
|
365
|
+
|
|
366
|
+
| Attribute | Meaning |
|
|
367
|
+
|---|---|
|
|
368
|
+
| `glasstrace.error.stack` | The bounded stack string (sanitized, then truncated). Treat this as input for product-side `StackSummary` parsing, not as a final agent-facing artifact. |
|
|
369
|
+
| `glasstrace.error.stack.truncated` | `true` if the original exceeded the byte budget and `...[stack truncated]` was appended. |
|
|
370
|
+
| `glasstrace.error.stack.redacted` | `true` if at least one sanitization rule modified the stack content (path normalization, URL query stripping, or credential redaction). |
|
|
371
|
+
|
|
372
|
+
Sanitization runs **before** truncation so credentials straddling
|
|
373
|
+
the truncation boundary are still removed from the visible portion.
|
|
374
|
+
The sanitizer:
|
|
375
|
+
|
|
376
|
+
- **Normalizes absolute paths.** A frame like
|
|
377
|
+
`at handler (/Users/erik/proj/src/api/handler.ts:5:1)` becomes
|
|
378
|
+
`at handler (<path>/src/api/handler.ts:5:1)`. The keep-from
|
|
379
|
+
marker set is `node_modules`, `.next`, `.glasstrace`, `src`,
|
|
380
|
+
`dist`, `build`, `lib`, `app`, `pages` (priority order). When no
|
|
381
|
+
marker matches, the path collapses to its basename so
|
|
382
|
+
`/var/private/secret/data.js` becomes `<path>/data.js`.
|
|
383
|
+
- **Strips URL query strings and fragments.**
|
|
384
|
+
`https://api.example.com/users?token=secret` becomes
|
|
385
|
+
`https://api.example.com/users`.
|
|
386
|
+
- **Redacts credentials** using the same pattern set as
|
|
387
|
+
response-body capture: `Bearer …`, JWT-shaped tokens,
|
|
388
|
+
Glasstrace API key prefixes (`gt_dev_*` / `gt_anon_*`), AWS
|
|
389
|
+
access keys (`AKIA…` / `ASIA…`), and `apikey`/`secret`/
|
|
390
|
+
`password`/`token` key-value pairs.
|
|
391
|
+
|
|
392
|
+
The byte budget is 8192 UTF-8 bytes. Truncation respects codepoint
|
|
393
|
+
boundaries so multi-byte characters are never split mid-sequence.
|
|
394
|
+
|
|
395
|
+
### Source provenance
|
|
396
|
+
|
|
397
|
+
When the exporter emits any of the new
|
|
398
|
+
`glasstrace.error.{message,code,stack,original_path,fallback_route}`
|
|
399
|
+
attributes, it also sets `glasstrace.error.source` to name the
|
|
400
|
+
surface that supplied the facts:
|
|
401
|
+
|
|
402
|
+
| Value | Source |
|
|
403
|
+
|---|---|
|
|
404
|
+
| `otel_exception` | OTel `recordException()` event (event name `"exception"`). |
|
|
405
|
+
| `otel_event` | An OTel-shape `exception.*` attribute set on the span itself instead of on an event. |
|
|
406
|
+
| `glasstrace_attribute` | A `glasstrace.error.*` attribute set explicitly by an adapter or user code. |
|
|
407
|
+
| `framework_runtime` | Reserved for a future framework-runtime probe. |
|
|
408
|
+
| `framework_fallback` | The framework rewrote the route to a fallback (e.g., `/_error`); see below. |
|
|
409
|
+
| `response_body` | Reserved for cases where the response body is the only error-bearing surface. |
|
|
410
|
+
|
|
411
|
+
Product consumers use the source to decide how to render
|
|
412
|
+
evidence (an `otel_exception` source can show the raw type and
|
|
413
|
+
message; `framework_fallback` is a softer signal that benefits
|
|
414
|
+
from the original-path context).
|
|
415
|
+
|
|
416
|
+
### Framework fallback markers
|
|
417
|
+
|
|
418
|
+
When a request reaches a framework fallback route — Next.js
|
|
419
|
+
`/_error`, `/_not-found`, `/_404`, `/_500` — the SDK preserves
|
|
420
|
+
the originally requested path so product consumers don't lose the
|
|
421
|
+
URL the user actually hit. Three additional attributes land on
|
|
422
|
+
the span:
|
|
423
|
+
|
|
424
|
+
| Attribute | Example |
|
|
425
|
+
|---|---|
|
|
426
|
+
| `glasstrace.error.original_path` | `/api/storage/missing/avatar.png` (path-only; no query, no fragment) |
|
|
427
|
+
| `glasstrace.error.fallback_route` | `/_error` |
|
|
428
|
+
| `glasstrace.error.framework.kind` | `"fallback"` |
|
|
429
|
+
|
|
430
|
+
The existing `glasstrace.route` attribute continues to carry
|
|
431
|
+
whatever the framework instrumentation reported (typically the
|
|
432
|
+
fallback route itself), so existing consumers are unaffected.
|
|
433
|
+
Product-side projection should prefer `glasstrace.error.original_path`
|
|
434
|
+
when present and fall back to `glasstrace.route` otherwise. The
|
|
435
|
+
markers fire only when the SDK observed a different requested URL
|
|
436
|
+
than the route — a real visit to `/_error` (an app could have a
|
|
437
|
+
real such page) is not flagged.
|
|
438
|
+
|
|
439
|
+
### What the SDK does NOT do
|
|
440
|
+
|
|
441
|
+
For agent-facing protection, several things are explicitly *not*
|
|
442
|
+
emitted from the SDK side:
|
|
443
|
+
|
|
444
|
+
- **No raw `exception.stacktrace`.** The string is always
|
|
445
|
+
sanitized before promotion to `glasstrace.error.stack`, and the
|
|
446
|
+
source-attribute path that bypassed enrichment never appears in
|
|
447
|
+
agent-facing MCP output (product ingestion projects only the
|
|
448
|
+
`glasstrace.*` family).
|
|
449
|
+
- **No fabricated stack frames** when `exception.stacktrace` was
|
|
450
|
+
not observed. Missing stack evidence stays missing; the
|
|
451
|
+
`glasstrace.error.stack*` attributes are simply absent.
|
|
452
|
+
- **No compile-diagnostic capture** in this version. If the SDK
|
|
453
|
+
cannot observe a Next.js compile error in the running mode, no
|
|
454
|
+
diagnostic is fabricated from the route name or status code.
|
|
455
|
+
Compile-diagnostic capture is a future feature gated on a
|
|
456
|
+
separate account capture-policy class.
|
|
457
|
+
- **No structured application logs.** Application logs are
|
|
458
|
+
outside the trace-evidence contract.
|
|
459
|
+
|
|
352
460
|
## Capturing side-effect evidence
|
|
353
461
|
|
|
354
462
|
When debugging a bug whose root cause is which side-effect operation
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
isDevApiKey,
|
|
6
6
|
readEnvLocalApiKey,
|
|
7
7
|
writeAndFsyncTempSync
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-WL6BXEJ5.js";
|
|
9
9
|
import {
|
|
10
10
|
AnonApiKeySchema
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-P45NZR4J.js";
|
|
12
12
|
import {
|
|
13
13
|
NEXT_CONFIG_NAMES
|
|
14
14
|
} from "./chunk-NB7GJE4S.js";
|
|
@@ -917,4 +917,4 @@ export {
|
|
|
917
917
|
writeShutdownMarker,
|
|
918
918
|
runUninit
|
|
919
919
|
};
|
|
920
|
-
//# sourceMappingURL=chunk-
|
|
920
|
+
//# sourceMappingURL=chunk-3PJP5Y3U.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-DQ25VOKK.js";
|
|
4
4
|
import {
|
|
5
5
|
GLASSTRACE_ATTRIBUTE_NAMES
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-P45NZR4J.js";
|
|
7
7
|
|
|
8
8
|
// src/errors.ts
|
|
9
9
|
var SdkError = class extends Error {
|
|
@@ -102,4 +102,4 @@ export {
|
|
|
102
102
|
GlasstraceSpanProcessor,
|
|
103
103
|
captureCorrelationId
|
|
104
104
|
};
|
|
105
|
-
//# sourceMappingURL=chunk-
|
|
105
|
+
//# sourceMappingURL=chunk-H57MQGNU.js.map
|
|
@@ -291,7 +291,7 @@ function generateInfoSection(agent, endpoint, sdkVersion) {
|
|
|
291
291
|
"- `get_error_list` - List recent errors with filtering and pagination",
|
|
292
292
|
"- `get_trace` - Get a specific trace by ID or URL pattern",
|
|
293
293
|
"- `get_root_cause` - Get the root cause analysis for a specific error trace (requires a `traceId` from `get_latest_error`, `get_error_list`, or `get_trace`)",
|
|
294
|
-
"- `get_test_suggestions` - Get test suggestions
|
|
294
|
+
"- `get_test_suggestions` - Get test suggestions for a specific error trace (requires a `traceId` from `get_latest_error`, `get_error_list`, or `get_trace`)",
|
|
295
295
|
"- `get_session_timeline` - Get the timeline of all traces in the current session",
|
|
296
296
|
"",
|
|
297
297
|
"To refresh this managed section after a `@glasstrace/sdk` upgrade, run: `npx glasstrace upgrade-instructions`. To reconfigure MCP credentials, run: `npx glasstrace mcp add`.",
|
|
@@ -332,4 +332,4 @@ export {
|
|
|
332
332
|
generateMcpConfig,
|
|
333
333
|
generateInfoSection
|
|
334
334
|
};
|
|
335
|
-
//# sourceMappingURL=chunk-
|
|
335
|
+
//# sourceMappingURL=chunk-KI7YJ7XD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent-detection/detect.ts","../src/agent-detection/configs.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { access, stat } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { constants } from \"node:fs\";\n\n/**\n * Describes an AI coding agent detected in a project.\n */\nexport interface DetectedAgent {\n name: \"claude\" | \"codex\" | \"gemini\" | \"cursor\" | \"windsurf\" | \"generic\";\n mcpConfigPath: string | null;\n infoFilePath: string | null;\n cliAvailable: boolean;\n registrationCommand: string | null;\n}\n\ntype AgentName = DetectedAgent[\"name\"];\n\ninterface AgentRule {\n name: AgentName;\n /** Paths relative to a search directory that indicate this agent is present. */\n markers: string[];\n /** Function to compute the MCP config path given the directory where markers were found. */\n mcpConfigPath: (markerDir: string) => string;\n /** Function to compute the info file path, or null. */\n infoFilePath: (markerDir: string) => string | null;\n /** CLI binary name to check in PATH, or null if no CLI exists. */\n cliBinary: string | null;\n /** Registration command template, or null. */\n registrationCommand: string | null;\n}\n\nconst AGENT_RULES: AgentRule[] = [\n {\n name: \"claude\",\n markers: [\".claude\", \"CLAUDE.md\"],\n mcpConfigPath: (dir) => join(dir, \".mcp.json\"),\n infoFilePath: (dir) => join(dir, \"CLAUDE.md\"),\n cliBinary: \"claude\",\n registrationCommand: \"npx glasstrace mcp add --agent claude\",\n },\n {\n name: \"codex\",\n markers: [\"codex.md\", \".codex\"],\n mcpConfigPath: (dir) => join(dir, \".codex\", \"config.toml\"),\n infoFilePath: (dir) => join(dir, \"codex.md\"),\n cliBinary: \"codex\",\n registrationCommand: \"npx glasstrace mcp add --agent codex\",\n },\n {\n name: \"gemini\",\n markers: [\".gemini\"],\n mcpConfigPath: (dir) => join(dir, \".gemini\", \"settings.json\"),\n infoFilePath: () => null,\n cliBinary: \"gemini\",\n registrationCommand: \"npx glasstrace mcp add --agent gemini\",\n },\n {\n name: \"cursor\",\n markers: [\".cursor\", \".cursorrules\"],\n mcpConfigPath: (dir) => join(dir, \".cursor\", \"mcp.json\"),\n infoFilePath: (dir) => join(dir, \".cursorrules\"),\n cliBinary: null,\n registrationCommand: \"npx glasstrace mcp add --agent cursor\",\n },\n {\n name: \"windsurf\",\n markers: [\".windsurfrules\", \".windsurf\"],\n mcpConfigPath: () =>\n join(homedir(), \".codeium\", \"windsurf\", \"mcp_config.json\"),\n infoFilePath: (dir) => join(dir, \".windsurfrules\"),\n cliBinary: null,\n registrationCommand: \"npx glasstrace mcp add --agent windsurf\",\n },\n];\n\n/**\n * Checks whether a path exists and is accessible, following symlinks.\n * Returns false on permission errors or missing paths.\n *\n * @param mode - The access mode to check (defaults to R_OK for marker detection).\n */\nasync function pathExists(\n path: string,\n mode: number = constants.R_OK,\n): Promise<boolean> {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Finds the git root directory by walking up from the given path.\n * Returns the starting directory if no `.git` is found.\n */\nasync function findGitRoot(startDir: string): Promise<string> {\n let current = resolve(startDir);\n\n while (true) {\n if (await pathExists(join(current, \".git\"), constants.F_OK)) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n // Reached filesystem root without finding .git\n break;\n }\n current = parent;\n }\n\n return resolve(startDir);\n}\n\n/**\n * Returns true if a CLI binary is available on PATH.\n * Uses `which` on Unix and `where` on Windows, via execFile (no shell injection).\n */\nfunction isCliAvailable(binary: string): Promise<boolean> {\n return new Promise((resolve) => {\n const command = process.platform === \"win32\" ? \"where\" : \"which\";\n execFile(command, [binary], (error) => {\n resolve(error === null);\n });\n });\n}\n\n/**\n * Detects AI coding agents present in a project by scanning for marker\n * files and directories. Walks up from projectRoot to the git root to\n * support monorepo layouts.\n *\n * Always includes a \"generic\" fallback entry.\n *\n * @param projectRoot - Absolute or relative path to the project directory.\n * @returns Array of detected agents, with generic always last.\n * @throws If projectRoot does not exist or is not a directory.\n */\nexport async function detectAgents(\n projectRoot: string,\n): Promise<DetectedAgent[]> {\n const resolvedRoot = resolve(projectRoot);\n\n // Validate projectRoot exists and is a directory\n let rootStat;\n try {\n rootStat = await stat(resolvedRoot);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n throw new Error(\n `projectRoot does not exist: ${resolvedRoot}` +\n (code ? ` (${code})` : \"\"),\n );\n }\n\n if (!rootStat.isDirectory()) {\n throw new Error(`projectRoot is not a directory: ${resolvedRoot}`);\n }\n\n const gitRoot = await findGitRoot(resolvedRoot);\n\n // Collect unique directories to search: projectRoot and every ancestor up to gitRoot\n const searchDirs: string[] = [];\n let current = resolvedRoot;\n while (true) {\n searchDirs.push(current);\n if (current === gitRoot) {\n break;\n }\n const parent = dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n const detected: DetectedAgent[] = [];\n const seenAgents = new Set<AgentName>();\n\n for (const rule of AGENT_RULES) {\n let foundDir: string | null = null;\n\n // Check each search directory for markers\n for (const dir of searchDirs) {\n let markerFound = false;\n for (const marker of rule.markers) {\n if (await pathExists(join(dir, marker))) {\n markerFound = true;\n break;\n }\n }\n if (markerFound) {\n foundDir = dir;\n break;\n }\n }\n\n if (foundDir === null) {\n continue;\n }\n\n if (seenAgents.has(rule.name)) {\n continue;\n }\n seenAgents.add(rule.name);\n\n // Determine info file path — only include if the file actually exists\n let infoFilePath = rule.infoFilePath(foundDir);\n if (infoFilePath !== null && !(await pathExists(infoFilePath))) {\n infoFilePath = null;\n }\n\n const cliAvailable = rule.cliBinary\n ? await isCliAvailable(rule.cliBinary)\n : false;\n\n detected.push({\n name: rule.name,\n mcpConfigPath: rule.mcpConfigPath(foundDir),\n infoFilePath,\n cliAvailable,\n registrationCommand: rule.registrationCommand,\n });\n }\n\n // Always include generic fallback\n detected.push({\n name: \"generic\",\n mcpConfigPath: join(resolvedRoot, \".glasstrace\", \"mcp.json\"),\n infoFilePath: null,\n cliAvailable: false,\n registrationCommand: null,\n });\n\n return detected;\n}\n","import type { DetectedAgent } from \"./detect.js\";\n\n/**\n * Generates the MCP server configuration content for a given agent.\n *\n * The output is the full file content suitable for writing to the agent's\n * MCP config file. The bearer token is intentionally embedded here for\n * agents whose schemas inline the Authorization header — Codex is the\n * exception and uses `bearer_token_env_var` so the actual token never\n * appears in TOML.\n *\n * @param agent - The detected agent to generate config for.\n * @param endpoint - The Glasstrace MCP endpoint URL.\n * @param bearer - The credential to embed in the Authorization header\n * (anon key or dev key, depending on the project's resolved\n * credential source). Empty values throw.\n * @returns The formatted configuration string.\n * @throws If endpoint or bearer is empty.\n */\nexport function generateMcpConfig(\n agent: DetectedAgent,\n endpoint: string,\n bearer: string,\n): string {\n if (!endpoint || endpoint.trim() === \"\") {\n throw new Error(\"endpoint must not be empty\");\n }\n if (!bearer || bearer.trim() === \"\") {\n throw new Error(\"bearer must not be empty\");\n }\n\n switch (agent.name) {\n case \"claude\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n type: \"http\",\n url: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"codex\": {\n // Escape TOML basic string special characters in the endpoint value.\n // TOML requires backslashes, quotes, and control characters to be escaped.\n const safeEndpoint = endpoint\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\");\n return [\n \"[mcp_servers.glasstrace]\",\n `url = \"${safeEndpoint}\"`,\n `bearer_token_env_var = \"GLASSTRACE_API_KEY\"`,\n \"\",\n ].join(\"\\n\");\n }\n\n case \"gemini\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n httpUrl: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"cursor\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n url: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"windsurf\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n serverUrl: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"generic\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n type: \"http\",\n url: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n default: {\n const _exhaustive: never = agent.name;\n throw new Error(`Unknown agent: ${_exhaustive}`);\n }\n }\n}\n\n/**\n * Strict pattern accepted as the value substituted into a `v=<sdkVersion>`\n * marker stamp. Covers the SDK's own published versions\n * (e.g. `1.4.0`, `0.0.0-canary-20260508120000`, `1.4.0+build.42`) without\n * admitting whitespace, angle-brackets, or terminal control sequences\n * that could be smuggled into the agent instruction file via a\n * malformed callsite.\n *\n * The stamp is the SDK semver string and nothing else (DISC-1592 / SDK-050\n * Required Semantics Item 1: \"the stamp encodes only the SDK semver\n * string ... it must not embed user-controlled or environment-derived\n * content\"). Reject anything outside this charset at the render site\n * rather than relying on the upstream `__SDK_VERSION__` define being\n * well-formed.\n */\nconst SDK_VERSION_STAMP_PATTERN = /^[A-Za-z0-9.+-]+$/;\n\n/**\n * Marker pair used to delimit the Glasstrace section in agent info files.\n */\ninterface MarkerPair {\n start: string;\n end: string;\n}\n\nfunction htmlMarkers(sdkVersion: string): MarkerPair {\n return {\n start: `<!-- glasstrace:mcp:start v=${sdkVersion} -->`,\n end: \"<!-- glasstrace:mcp:end -->\",\n };\n}\n\nfunction hashMarkers(sdkVersion: string): MarkerPair {\n return {\n start: `# glasstrace:mcp:start v=${sdkVersion}`,\n end: \"# glasstrace:mcp:end\",\n };\n}\n\n/**\n * Generates informational content for an agent's instruction file.\n *\n * This content is designed to be appended to or inserted into agent-specific\n * instruction files (CLAUDE.md, .cursorrules, codex.md). It contains ONLY\n * the endpoint URL, tool descriptions, and setup instructions. Auth tokens\n * are NEVER included in this output.\n *\n * The rendered block opens with a cost-aware cross-tool decision paragraph\n * (DISC-1593 / SDK-050) telling the user's AI agent **when** Glasstrace\n * MCP is worth calling at all and **which** tool is the cheapest first\n * call for each symptom class. The start marker carries a `v=<sdkVersion>`\n * stamp (DISC-1592 / SDK-050) so a later `glasstrace upgrade-instructions`\n * run — and the SDK's stale-section warning at init — can detect that\n * the file was rendered by an older SDK and refresh the block.\n *\n * @param agent - The detected agent to generate info for.\n * @param endpoint - The Glasstrace MCP endpoint URL.\n * @param sdkVersion - The SDK semver string to embed in the start marker\n * (e.g. `1.4.0`, `0.0.0-canary-20260508120000`). Must match\n * `[A-Za-z0-9.+\\-]+`; arbitrary or empty values throw.\n * @returns The formatted info section string, or empty string for agents without a supported info file format.\n * @throws If endpoint is empty, or if sdkVersion is empty or contains\n * characters outside the accepted stamp charset.\n */\nexport function generateInfoSection(\n agent: DetectedAgent,\n endpoint: string,\n sdkVersion: string,\n): string {\n if (!endpoint || endpoint.trim() === \"\") {\n throw new Error(\"endpoint must not be empty\");\n }\n if (!sdkVersion || sdkVersion.trim() === \"\") {\n throw new Error(\"sdkVersion must not be empty\");\n }\n if (!SDK_VERSION_STAMP_PATTERN.test(sdkVersion)) {\n throw new Error(\n \"sdkVersion must match [A-Za-z0-9.+\\\\-]+ (semver-shaped, no whitespace, no angle brackets)\",\n );\n }\n\n // Cost-aware cross-tool decision paragraph (DISC-1593 / SDK-050\n // Required Semantics §1). Load-bearing semantics:\n // 1. Frame Glasstrace MCP as conditionally worth calling.\n // 2. Name cheapest-orientation routing per symptom class.\n // 3. Restate the no-candidates / no_traces_found \"scoped retrieval\n // result, not absence of the bug\" contract.\n // 4. List the conditions that justify calling Glasstrace MCP at all.\n // Wording aligned with MCP-025's planned `recoveryActions` so the two\n // surfaces do not contradict each other.\n const content = [\n \"\",\n \"## Glasstrace MCP Integration\",\n \"\",\n `Glasstrace is configured as an MCP server at: ${endpoint}`,\n \"\",\n \"Glasstrace MCP is available when runtime evidence would materially reduce uncertainty. Use it when there is a failing request, stack trace, unclear runtime behavior, race/data-flow symptom, side effect, or performance issue that source inspection alone does not explain. For a current error, `get_latest_error` or `get_error_list` is usually the cheapest orientation call. For a known route/procedure with no exact error, use `find_trace_candidates` and follow returned exact `get_trace` or `get_root_cause` arguments only if the candidates look relevant. Do not call trace tools for trivial source-local fixes. Treat **no candidates** or **no_traces_found** as a scoped retrieval result, not proof the bug is absent.\",\n \"\",\n \"Available tools:\",\n \"- `get_latest_error` - Get the most recent error trace from the current session\",\n \"- `find_trace_candidates` - First-contact route/procedure/URL candidate selection when you have a route fragment, tRPC procedure, method, status, or rough recent activity window but not the exact trace ID. Returns candidate traces plus suggested `get_trace` / `get_root_cause` follow-up call arguments. Candidate discovery, not root-cause proof.\",\n \"- `get_error_list` - List recent errors with filtering and pagination\",\n \"- `get_trace` - Get a specific trace by ID or URL pattern\",\n \"- `get_root_cause` - Get the root cause analysis for a specific error trace (requires a `traceId` from `get_latest_error`, `get_error_list`, or `get_trace`)\",\n \"- `get_test_suggestions` - Get test suggestions based on recent errors\",\n \"- `get_session_timeline` - Get the timeline of all traces in the current session\",\n \"\",\n \"To refresh this managed section after a `@glasstrace/sdk` upgrade, run: `npx glasstrace upgrade-instructions`. To reconfigure MCP credentials, run: `npx glasstrace mcp add`.\",\n \"\",\n ].join(\"\\n\");\n\n switch (agent.name) {\n case \"claude\": {\n const m = htmlMarkers(sdkVersion);\n return `${m.start}\\n${content}${m.end}\\n`;\n }\n\n case \"codex\": {\n const m = htmlMarkers(sdkVersion);\n return `${m.start}\\n${content}${m.end}\\n`;\n }\n\n case \"cursor\": {\n const m = hashMarkers(sdkVersion);\n return `${m.start}\\n${content}${m.end}\\n`;\n }\n\n case \"gemini\":\n case \"windsurf\":\n case \"generic\":\n return \"\";\n\n default: {\n const _exhaustive: never = agent.name;\n throw new Error(`Unknown agent: ${_exhaustive}`);\n }\n }\n}\n"],"mappings":"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","names":["resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent-detection/detect.ts","../src/agent-detection/configs.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { access, stat } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { constants } from \"node:fs\";\n\n/**\n * Describes an AI coding agent detected in a project.\n */\nexport interface DetectedAgent {\n name: \"claude\" | \"codex\" | \"gemini\" | \"cursor\" | \"windsurf\" | \"generic\";\n mcpConfigPath: string | null;\n infoFilePath: string | null;\n cliAvailable: boolean;\n registrationCommand: string | null;\n}\n\ntype AgentName = DetectedAgent[\"name\"];\n\ninterface AgentRule {\n name: AgentName;\n /** Paths relative to a search directory that indicate this agent is present. */\n markers: string[];\n /** Function to compute the MCP config path given the directory where markers were found. */\n mcpConfigPath: (markerDir: string) => string;\n /** Function to compute the info file path, or null. */\n infoFilePath: (markerDir: string) => string | null;\n /** CLI binary name to check in PATH, or null if no CLI exists. */\n cliBinary: string | null;\n /** Registration command template, or null. */\n registrationCommand: string | null;\n}\n\nconst AGENT_RULES: AgentRule[] = [\n {\n name: \"claude\",\n markers: [\".claude\", \"CLAUDE.md\"],\n mcpConfigPath: (dir) => join(dir, \".mcp.json\"),\n infoFilePath: (dir) => join(dir, \"CLAUDE.md\"),\n cliBinary: \"claude\",\n registrationCommand: \"npx glasstrace mcp add --agent claude\",\n },\n {\n name: \"codex\",\n markers: [\"codex.md\", \".codex\"],\n mcpConfigPath: (dir) => join(dir, \".codex\", \"config.toml\"),\n infoFilePath: (dir) => join(dir, \"codex.md\"),\n cliBinary: \"codex\",\n registrationCommand: \"npx glasstrace mcp add --agent codex\",\n },\n {\n name: \"gemini\",\n markers: [\".gemini\"],\n mcpConfigPath: (dir) => join(dir, \".gemini\", \"settings.json\"),\n infoFilePath: () => null,\n cliBinary: \"gemini\",\n registrationCommand: \"npx glasstrace mcp add --agent gemini\",\n },\n {\n name: \"cursor\",\n markers: [\".cursor\", \".cursorrules\"],\n mcpConfigPath: (dir) => join(dir, \".cursor\", \"mcp.json\"),\n infoFilePath: (dir) => join(dir, \".cursorrules\"),\n cliBinary: null,\n registrationCommand: \"npx glasstrace mcp add --agent cursor\",\n },\n {\n name: \"windsurf\",\n markers: [\".windsurfrules\", \".windsurf\"],\n mcpConfigPath: () =>\n join(homedir(), \".codeium\", \"windsurf\", \"mcp_config.json\"),\n infoFilePath: (dir) => join(dir, \".windsurfrules\"),\n cliBinary: null,\n registrationCommand: \"npx glasstrace mcp add --agent windsurf\",\n },\n];\n\n/**\n * Checks whether a path exists and is accessible, following symlinks.\n * Returns false on permission errors or missing paths.\n *\n * @param mode - The access mode to check (defaults to R_OK for marker detection).\n */\nasync function pathExists(\n path: string,\n mode: number = constants.R_OK,\n): Promise<boolean> {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Finds the git root directory by walking up from the given path.\n * Returns the starting directory if no `.git` is found.\n */\nasync function findGitRoot(startDir: string): Promise<string> {\n let current = resolve(startDir);\n\n while (true) {\n if (await pathExists(join(current, \".git\"), constants.F_OK)) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n // Reached filesystem root without finding .git\n break;\n }\n current = parent;\n }\n\n return resolve(startDir);\n}\n\n/**\n * Returns true if a CLI binary is available on PATH.\n * Uses `which` on Unix and `where` on Windows, via execFile (no shell injection).\n */\nfunction isCliAvailable(binary: string): Promise<boolean> {\n return new Promise((resolve) => {\n const command = process.platform === \"win32\" ? \"where\" : \"which\";\n execFile(command, [binary], (error) => {\n resolve(error === null);\n });\n });\n}\n\n/**\n * Detects AI coding agents present in a project by scanning for marker\n * files and directories. Walks up from projectRoot to the git root to\n * support monorepo layouts.\n *\n * Always includes a \"generic\" fallback entry.\n *\n * @param projectRoot - Absolute or relative path to the project directory.\n * @returns Array of detected agents, with generic always last.\n * @throws If projectRoot does not exist or is not a directory.\n */\nexport async function detectAgents(\n projectRoot: string,\n): Promise<DetectedAgent[]> {\n const resolvedRoot = resolve(projectRoot);\n\n // Validate projectRoot exists and is a directory\n let rootStat;\n try {\n rootStat = await stat(resolvedRoot);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n throw new Error(\n `projectRoot does not exist: ${resolvedRoot}` +\n (code ? ` (${code})` : \"\"),\n );\n }\n\n if (!rootStat.isDirectory()) {\n throw new Error(`projectRoot is not a directory: ${resolvedRoot}`);\n }\n\n const gitRoot = await findGitRoot(resolvedRoot);\n\n // Collect unique directories to search: projectRoot and every ancestor up to gitRoot\n const searchDirs: string[] = [];\n let current = resolvedRoot;\n while (true) {\n searchDirs.push(current);\n if (current === gitRoot) {\n break;\n }\n const parent = dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n const detected: DetectedAgent[] = [];\n const seenAgents = new Set<AgentName>();\n\n for (const rule of AGENT_RULES) {\n let foundDir: string | null = null;\n\n // Check each search directory for markers\n for (const dir of searchDirs) {\n let markerFound = false;\n for (const marker of rule.markers) {\n if (await pathExists(join(dir, marker))) {\n markerFound = true;\n break;\n }\n }\n if (markerFound) {\n foundDir = dir;\n break;\n }\n }\n\n if (foundDir === null) {\n continue;\n }\n\n if (seenAgents.has(rule.name)) {\n continue;\n }\n seenAgents.add(rule.name);\n\n // Determine info file path — only include if the file actually exists\n let infoFilePath = rule.infoFilePath(foundDir);\n if (infoFilePath !== null && !(await pathExists(infoFilePath))) {\n infoFilePath = null;\n }\n\n const cliAvailable = rule.cliBinary\n ? await isCliAvailable(rule.cliBinary)\n : false;\n\n detected.push({\n name: rule.name,\n mcpConfigPath: rule.mcpConfigPath(foundDir),\n infoFilePath,\n cliAvailable,\n registrationCommand: rule.registrationCommand,\n });\n }\n\n // Always include generic fallback\n detected.push({\n name: \"generic\",\n mcpConfigPath: join(resolvedRoot, \".glasstrace\", \"mcp.json\"),\n infoFilePath: null,\n cliAvailable: false,\n registrationCommand: null,\n });\n\n return detected;\n}\n","import type { DetectedAgent } from \"./detect.js\";\n\n/**\n * Generates the MCP server configuration content for a given agent.\n *\n * The output is the full file content suitable for writing to the agent's\n * MCP config file. The bearer token is intentionally embedded here for\n * agents whose schemas inline the Authorization header — Codex is the\n * exception and uses `bearer_token_env_var` so the actual token never\n * appears in TOML.\n *\n * @param agent - The detected agent to generate config for.\n * @param endpoint - The Glasstrace MCP endpoint URL.\n * @param bearer - The credential to embed in the Authorization header\n * (anon key or dev key, depending on the project's resolved\n * credential source). Empty values throw.\n * @returns The formatted configuration string.\n * @throws If endpoint or bearer is empty.\n */\nexport function generateMcpConfig(\n agent: DetectedAgent,\n endpoint: string,\n bearer: string,\n): string {\n if (!endpoint || endpoint.trim() === \"\") {\n throw new Error(\"endpoint must not be empty\");\n }\n if (!bearer || bearer.trim() === \"\") {\n throw new Error(\"bearer must not be empty\");\n }\n\n switch (agent.name) {\n case \"claude\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n type: \"http\",\n url: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"codex\": {\n // Escape TOML basic string special characters in the endpoint value.\n // TOML requires backslashes, quotes, and control characters to be escaped.\n const safeEndpoint = endpoint\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\");\n return [\n \"[mcp_servers.glasstrace]\",\n `url = \"${safeEndpoint}\"`,\n `bearer_token_env_var = \"GLASSTRACE_API_KEY\"`,\n \"\",\n ].join(\"\\n\");\n }\n\n case \"gemini\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n httpUrl: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"cursor\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n url: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"windsurf\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n serverUrl: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n case \"generic\":\n return JSON.stringify(\n {\n mcpServers: {\n glasstrace: {\n type: \"http\",\n url: endpoint,\n headers: {\n Authorization: `Bearer ${bearer}`,\n },\n },\n },\n },\n null,\n 2,\n );\n\n default: {\n const _exhaustive: never = agent.name;\n throw new Error(`Unknown agent: ${_exhaustive}`);\n }\n }\n}\n\n/**\n * Strict pattern accepted as the value substituted into a `v=<sdkVersion>`\n * marker stamp. Covers the SDK's own published versions\n * (e.g. `1.4.0`, `0.0.0-canary-20260508120000`, `1.4.0+build.42`) without\n * admitting whitespace, angle-brackets, or terminal control sequences\n * that could be smuggled into the agent instruction file via a\n * malformed callsite.\n *\n * The stamp is the SDK semver string and nothing else (DISC-1592 / SDK-050\n * Required Semantics Item 1: \"the stamp encodes only the SDK semver\n * string ... it must not embed user-controlled or environment-derived\n * content\"). Reject anything outside this charset at the render site\n * rather than relying on the upstream `__SDK_VERSION__` define being\n * well-formed.\n */\nconst SDK_VERSION_STAMP_PATTERN = /^[A-Za-z0-9.+-]+$/;\n\n/**\n * Marker pair used to delimit the Glasstrace section in agent info files.\n */\ninterface MarkerPair {\n start: string;\n end: string;\n}\n\nfunction htmlMarkers(sdkVersion: string): MarkerPair {\n return {\n start: `<!-- glasstrace:mcp:start v=${sdkVersion} -->`,\n end: \"<!-- glasstrace:mcp:end -->\",\n };\n}\n\nfunction hashMarkers(sdkVersion: string): MarkerPair {\n return {\n start: `# glasstrace:mcp:start v=${sdkVersion}`,\n end: \"# glasstrace:mcp:end\",\n };\n}\n\n/**\n * Generates informational content for an agent's instruction file.\n *\n * This content is designed to be appended to or inserted into agent-specific\n * instruction files (CLAUDE.md, .cursorrules, codex.md). It contains ONLY\n * the endpoint URL, tool descriptions, and setup instructions. Auth tokens\n * are NEVER included in this output.\n *\n * The rendered block opens with a cost-aware cross-tool decision paragraph\n * (DISC-1593 / SDK-050) telling the user's AI agent **when** Glasstrace\n * MCP is worth calling at all and **which** tool is the cheapest first\n * call for each symptom class. The start marker carries a `v=<sdkVersion>`\n * stamp (DISC-1592 / SDK-050) so a later `glasstrace upgrade-instructions`\n * run — and the SDK's stale-section warning at init — can detect that\n * the file was rendered by an older SDK and refresh the block.\n *\n * @param agent - The detected agent to generate info for.\n * @param endpoint - The Glasstrace MCP endpoint URL.\n * @param sdkVersion - The SDK semver string to embed in the start marker\n * (e.g. `1.4.0`, `0.0.0-canary-20260508120000`). Must match\n * `[A-Za-z0-9.+\\-]+`; arbitrary or empty values throw.\n * @returns The formatted info section string, or empty string for agents without a supported info file format.\n * @throws If endpoint is empty, or if sdkVersion is empty or contains\n * characters outside the accepted stamp charset.\n */\nexport function generateInfoSection(\n agent: DetectedAgent,\n endpoint: string,\n sdkVersion: string,\n): string {\n if (!endpoint || endpoint.trim() === \"\") {\n throw new Error(\"endpoint must not be empty\");\n }\n if (!sdkVersion || sdkVersion.trim() === \"\") {\n throw new Error(\"sdkVersion must not be empty\");\n }\n if (!SDK_VERSION_STAMP_PATTERN.test(sdkVersion)) {\n throw new Error(\n \"sdkVersion must match [A-Za-z0-9.+\\\\-]+ (semver-shaped, no whitespace, no angle brackets)\",\n );\n }\n\n // Cost-aware cross-tool decision paragraph (DISC-1593 / SDK-050\n // Required Semantics §1). Load-bearing semantics:\n // 1. Frame Glasstrace MCP as conditionally worth calling.\n // 2. Name cheapest-orientation routing per symptom class.\n // 3. Restate the no-candidates / no_traces_found \"scoped retrieval\n // result, not absence of the bug\" contract.\n // 4. List the conditions that justify calling Glasstrace MCP at all.\n // Wording aligned with MCP-025's planned `recoveryActions` so the two\n // surfaces do not contradict each other.\n const content = [\n \"\",\n \"## Glasstrace MCP Integration\",\n \"\",\n `Glasstrace is configured as an MCP server at: ${endpoint}`,\n \"\",\n \"Glasstrace MCP is available when runtime evidence would materially reduce uncertainty. Use it when there is a failing request, stack trace, unclear runtime behavior, race/data-flow symptom, side effect, or performance issue that source inspection alone does not explain. For a current error, `get_latest_error` or `get_error_list` is usually the cheapest orientation call. For a known route/procedure with no exact error, use `find_trace_candidates` and follow returned exact `get_trace` or `get_root_cause` arguments only if the candidates look relevant. Do not call trace tools for trivial source-local fixes. Treat **no candidates** or **no_traces_found** as a scoped retrieval result, not proof the bug is absent.\",\n \"\",\n \"Available tools:\",\n \"- `get_latest_error` - Get the most recent error trace from the current session\",\n \"- `find_trace_candidates` - First-contact route/procedure/URL candidate selection when you have a route fragment, tRPC procedure, method, status, or rough recent activity window but not the exact trace ID. Returns candidate traces plus suggested `get_trace` / `get_root_cause` follow-up call arguments. Candidate discovery, not root-cause proof.\",\n \"- `get_error_list` - List recent errors with filtering and pagination\",\n \"- `get_trace` - Get a specific trace by ID or URL pattern\",\n \"- `get_root_cause` - Get the root cause analysis for a specific error trace (requires a `traceId` from `get_latest_error`, `get_error_list`, or `get_trace`)\",\n \"- `get_test_suggestions` - Get test suggestions for a specific error trace (requires a `traceId` from `get_latest_error`, `get_error_list`, or `get_trace`)\",\n \"- `get_session_timeline` - Get the timeline of all traces in the current session\",\n \"\",\n \"To refresh this managed section after a `@glasstrace/sdk` upgrade, run: `npx glasstrace upgrade-instructions`. To reconfigure MCP credentials, run: `npx glasstrace mcp add`.\",\n \"\",\n ].join(\"\\n\");\n\n switch (agent.name) {\n case \"claude\": {\n const m = htmlMarkers(sdkVersion);\n return `${m.start}\\n${content}${m.end}\\n`;\n }\n\n case \"codex\": {\n const m = htmlMarkers(sdkVersion);\n return `${m.start}\\n${content}${m.end}\\n`;\n }\n\n case \"cursor\": {\n const m = hashMarkers(sdkVersion);\n return `${m.start}\\n${content}${m.end}\\n`;\n }\n\n case \"gemini\":\n case \"windsurf\":\n case \"generic\":\n return \"\";\n\n default: {\n const _exhaustive: never = agent.name;\n throw new Error(`Unknown agent: ${_exhaustive}`);\n }\n }\n}\n"],"mappings":"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","names":["resolve"]}
|
|
@@ -2,12 +2,12 @@ import {
|
|
|
2
2
|
atomicWriteFile,
|
|
3
3
|
refreshGenericMcpConfigAtRuntime,
|
|
4
4
|
resolveEffectiveMcpCredential
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WL6BXEJ5.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_CAPTURE_CONFIG,
|
|
8
8
|
SdkCachedConfigSchema,
|
|
9
9
|
SdkInitResponseSchema
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-P45NZR4J.js";
|
|
11
11
|
import {
|
|
12
12
|
__require
|
|
13
13
|
} from "./chunk-NSBPE2FW.js";
|
|
@@ -692,4 +692,4 @@ export {
|
|
|
692
692
|
didLastInitSucceed,
|
|
693
693
|
verifyInitReachable
|
|
694
694
|
};
|
|
695
|
-
//# sourceMappingURL=chunk-
|
|
695
|
+
//# sourceMappingURL=chunk-M2TLX6NM.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createBuildHash
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P45NZR4J.js";
|
|
4
4
|
|
|
5
5
|
// src/import-graph.ts
|
|
6
6
|
import * as fs from "node:fs/promises";
|
|
@@ -175,4 +175,4 @@ export {
|
|
|
175
175
|
extractImports,
|
|
176
176
|
buildImportGraph
|
|
177
177
|
};
|
|
178
|
-
//# sourceMappingURL=chunk-
|
|
178
|
+
//# sourceMappingURL=chunk-NN5YCETI.js.map
|
|
@@ -13850,6 +13850,26 @@ var GLASSTRACE_ATTRIBUTE_NAMES = {
|
|
|
13850
13850
|
ERROR_CODE: "glasstrace.error.code",
|
|
13851
13851
|
ERROR_CATEGORY: "glasstrace.error.category",
|
|
13852
13852
|
ERROR_FIELD: "glasstrace.error.field",
|
|
13853
|
+
// Error evidence v1 (SDK-041 / DISC-1535).
|
|
13854
|
+
// Additive to the existing `glasstrace.error.*` family. Bounded
|
|
13855
|
+
// stacktrace input for the product-side StackSummary parser
|
|
13856
|
+
// (SCHEMA-033); plus framework-fallback markers so the original
|
|
13857
|
+
// request path is preserved when Next.js (or another framework)
|
|
13858
|
+
// rewrites the route to a fallback like `/_error` or `/_not-found`;
|
|
13859
|
+
// plus a source-provenance enum so product can tell which surface
|
|
13860
|
+
// emitted each error fact (`exception.message` event vs span attr
|
|
13861
|
+
// vs response body vs framework runtime).
|
|
13862
|
+
//
|
|
13863
|
+
// Wire keys remain in `glasstrace.error.*` for namespace consistency
|
|
13864
|
+
// with the Tier-1 `error.message` / `error.code` / `error.category`
|
|
13865
|
+
// attributes already in this registry.
|
|
13866
|
+
ERROR_STACK: "glasstrace.error.stack",
|
|
13867
|
+
ERROR_STACK_TRUNCATED: "glasstrace.error.stack.truncated",
|
|
13868
|
+
ERROR_STACK_REDACTED: "glasstrace.error.stack.redacted",
|
|
13869
|
+
ERROR_SOURCE: "glasstrace.error.source",
|
|
13870
|
+
ERROR_FRAMEWORK_KIND: "glasstrace.error.framework.kind",
|
|
13871
|
+
ERROR_ORIGINAL_PATH: "glasstrace.error.original_path",
|
|
13872
|
+
ERROR_FALLBACK_ROUTE: "glasstrace.error.fallback_route",
|
|
13853
13873
|
ORM_PROVIDER: "glasstrace.orm.provider",
|
|
13854
13874
|
ORM_MODEL: "glasstrace.orm.model",
|
|
13855
13875
|
ORM_OPERATION: "glasstrace.orm.operation",
|
|
@@ -14238,4 +14258,4 @@ export {
|
|
|
14238
14258
|
SIDE_EFFECT_OPERATION_STATUSES,
|
|
14239
14259
|
SIDE_EFFECT_OPERATION_PHASES
|
|
14240
14260
|
};
|
|
14241
|
-
//# sourceMappingURL=chunk-
|
|
14261
|
+
//# sourceMappingURL=chunk-P45NZR4J.js.map
|