@glasstrace/sdk 1.9.1 → 1.10.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/dist/async-context/index.cjs +44 -0
- package/dist/async-context/index.cjs.map +1 -1
- package/dist/async-context/index.js +2 -2
- package/dist/{chunk-JHUNLPSS.js → chunk-6RKS3DNA.js} +45 -1
- package/dist/{chunk-JHUNLPSS.js.map → chunk-6RKS3DNA.js.map} +1 -1
- package/dist/{chunk-HD6JIFKN.js → chunk-BSVWJSVX.js} +2 -2
- package/dist/{chunk-QOHKZOKB.js → chunk-D54FMQHF.js} +2 -2
- package/dist/chunk-I2DVVSKW.js +419 -0
- package/dist/chunk-I2DVVSKW.js.map +1 -0
- package/dist/{chunk-H6WJ63X2.js → chunk-M5GO2SSO.js} +2 -2
- package/dist/{chunk-QEXRCXSY.js → chunk-OXM2BZMF.js} +2 -2
- package/dist/{chunk-M6EWJCAT.js → chunk-QVTONMVZ.js} +2 -2
- package/dist/{chunk-DKV53A2C.js → chunk-RL43PU2X.js} +2 -2
- package/dist/{chunk-KI7YJ7XD.js → chunk-TJ46YOGJ.js} +42 -22
- package/dist/chunk-TJ46YOGJ.js.map +1 -0
- package/dist/{chunk-GWIEUBFR.js → chunk-UMGZJYC4.js} +3 -3
- package/dist/{chunk-2F2MGFLO.js → chunk-WQF7ZQOM.js} +39 -405
- package/dist/chunk-WQF7ZQOM.js.map +1 -0
- package/dist/{chunk-QXITSNYM.js → chunk-XG6WR2KS.js} +3 -3
- package/dist/cli/init.cjs +51 -25
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +8 -8
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +42 -22
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +4 -4
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/uninit.js +3 -3
- package/dist/cli/upgrade-instructions.cjs +39 -21
- package/dist/cli/upgrade-instructions.cjs.map +1 -1
- package/dist/cli/upgrade-instructions.js +4 -4
- package/dist/cli/upgrade-instructions.js.map +1 -1
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.js +2 -2
- package/dist/edge-entry.cjs +44 -0
- package/dist/edge-entry.cjs.map +1 -1
- package/dist/edge-entry.js +4 -4
- package/dist/index.cjs +58 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.cjs +44 -0
- package/dist/middleware/index.cjs.map +1 -1
- package/dist/middleware/index.js +2 -2
- package/dist/node-entry.cjs +58 -5
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +12 -10
- package/dist/node-subpath.cjs.map +1 -1
- package/dist/node-subpath.js +3 -3
- package/dist/{source-map-uploader-MMJ2WCL4.js → source-map-uploader-CLYCE2TZ.js} +3 -3
- package/dist/trpc/index.cjs +15164 -503
- package/dist/trpc/index.cjs.map +1 -1
- package/dist/trpc/index.d.cts +62 -1
- package/dist/trpc/index.d.ts +62 -1
- package/dist/trpc/index.js +200 -1
- package/dist/trpc/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2F2MGFLO.js.map +0 -1
- package/dist/chunk-KI7YJ7XD.js.map +0 -1
- /package/dist/{chunk-HD6JIFKN.js.map → chunk-BSVWJSVX.js.map} +0 -0
- /package/dist/{chunk-QOHKZOKB.js.map → chunk-D54FMQHF.js.map} +0 -0
- /package/dist/{chunk-H6WJ63X2.js.map → chunk-M5GO2SSO.js.map} +0 -0
- /package/dist/{chunk-QEXRCXSY.js.map → chunk-OXM2BZMF.js.map} +0 -0
- /package/dist/{chunk-M6EWJCAT.js.map → chunk-QVTONMVZ.js.map} +0 -0
- /package/dist/{chunk-DKV53A2C.js.map → chunk-RL43PU2X.js.map} +0 -0
- /package/dist/{chunk-GWIEUBFR.js.map → chunk-UMGZJYC4.js.map} +0 -0
- /package/dist/{chunk-QXITSNYM.js.map → chunk-XG6WR2KS.js.map} +0 -0
- /package/dist/{source-map-uploader-MMJ2WCL4.js.map → source-map-uploader-CLYCE2TZ.js.map} +0 -0
|
@@ -151,6 +151,43 @@ async function detectAgents(projectRoot) {
|
|
|
151
151
|
return detected;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
// src/agent-detection/agent-instruction-text.ts
|
|
155
|
+
function buildAgentInstructionBody() {
|
|
156
|
+
return [
|
|
157
|
+
"",
|
|
158
|
+
"## Glasstrace MCP \u2014 Runtime Debugging Evidence",
|
|
159
|
+
"",
|
|
160
|
+
"Glasstrace is connected via MCP (`glasstrace`). It captures runtime traces from this app and exposes them through tools that disambiguate bugs source alone cannot resolve.",
|
|
161
|
+
"",
|
|
162
|
+
"### Call Glasstrace FIRST when:",
|
|
163
|
+
"- A value passed at runtime is suspect: wrong role, locale, timezone, template, tenant id, or any enum/config that branches downstream.",
|
|
164
|
+
"- The bug is in a side-effect operation: email sent, calendar event created, webhook dispatched, queued job, `after()` callback.",
|
|
165
|
+
"- The user reports a symptom but you do not yet know which code path actually executed.",
|
|
166
|
+
"- You need to confirm a route or procedure ran in the relevant time window before doing a source dive.",
|
|
167
|
+
"",
|
|
168
|
+
"### SKIP Glasstrace when:",
|
|
169
|
+
"- The bug is statically obvious from source (N+1 query, missing await, redundant query, type error, missing null check).",
|
|
170
|
+
"- The change is a refactor whose correctness does not depend on runtime behavior.",
|
|
171
|
+
"- You already have a precise traceId from another source.",
|
|
172
|
+
"",
|
|
173
|
+
"### Workflow",
|
|
174
|
+
"1. Start with `find_trace_candidates`. Pass whatever route or procedure name is natural \u2014 the server normalizes vocabulary and, on miss, returns close matches and a sample of routes actually present in the window.",
|
|
175
|
+
"2. Take the highest-confidence candidate's `suggestedFollowups` and pass them straight to `get_trace` or `get_root_cause`.",
|
|
176
|
+
"3. For side-effect bugs, read `sideEffectSummary` in the `get_trace` / `get_root_cause` response. The allowlisted fields (`templateKey`, `providerOperation`, `role`, `locale`, `timezone`, `status`, `phase`) are the ones that disambiguate payload bugs.",
|
|
177
|
+
"4. If a tool returns empty, READ the response's `closeMatches`, `recentRoutesSample`, and `recoveryActions` before pivoting to source. Empty results carry `notAbsenceProof: true` \u2014 they are never proof the bug did not occur.",
|
|
178
|
+
"",
|
|
179
|
+
"### Tools",
|
|
180
|
+
"- `find_trace_candidates` \u2014 discovery, vocabulary-tolerant filter",
|
|
181
|
+
"- `get_trace` \u2014 exact trace by `traceId`",
|
|
182
|
+
"- `get_root_cause` \u2014 root-cause analysis for a `traceId`",
|
|
183
|
+
"- `get_session_timeline` \u2014 events for a session",
|
|
184
|
+
"- `get_latest_error` / `get_error_list` \u2014 recent server errors",
|
|
185
|
+
"",
|
|
186
|
+
"Side-effect evidence is allowlisted and compact by design. Fields you don't see may have been omitted by policy, not absent at runtime.",
|
|
187
|
+
""
|
|
188
|
+
].join("\n");
|
|
189
|
+
}
|
|
190
|
+
|
|
154
191
|
// src/agent-detection/configs.ts
|
|
155
192
|
function generateMcpConfig(agent, endpoint, bearer) {
|
|
156
193
|
if (!endpoint || endpoint.trim() === "") {
|
|
@@ -205,6 +242,7 @@ function generateMcpConfig(agent, endpoint, bearer) {
|
|
|
205
242
|
{
|
|
206
243
|
mcpServers: {
|
|
207
244
|
glasstrace: {
|
|
245
|
+
type: "http",
|
|
208
246
|
url: endpoint,
|
|
209
247
|
headers: {
|
|
210
248
|
Authorization: `Bearer ${bearer}`
|
|
@@ -220,7 +258,8 @@ function generateMcpConfig(agent, endpoint, bearer) {
|
|
|
220
258
|
{
|
|
221
259
|
mcpServers: {
|
|
222
260
|
glasstrace: {
|
|
223
|
-
|
|
261
|
+
type: "http",
|
|
262
|
+
url: endpoint,
|
|
224
263
|
headers: {
|
|
225
264
|
Authorization: `Bearer ${bearer}`
|
|
226
265
|
}
|
|
@@ -277,26 +316,7 @@ function generateInfoSection(agent, endpoint, sdkVersion) {
|
|
|
277
316
|
"sdkVersion must match [A-Za-z0-9.+\\-]+ (semver-shaped, no whitespace, no angle brackets)"
|
|
278
317
|
);
|
|
279
318
|
}
|
|
280
|
-
const content =
|
|
281
|
-
"",
|
|
282
|
-
"## Glasstrace MCP Integration",
|
|
283
|
-
"",
|
|
284
|
-
`Glasstrace is configured as an MCP server at: ${endpoint}`,
|
|
285
|
-
"",
|
|
286
|
-
"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.",
|
|
287
|
-
"",
|
|
288
|
-
"Available tools:",
|
|
289
|
-
"- `get_latest_error` - Get the most recent error trace from the current session",
|
|
290
|
-
"- `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.",
|
|
291
|
-
"- `get_error_list` - List recent errors with filtering and pagination",
|
|
292
|
-
"- `get_trace` - Get a specific trace by ID or URL pattern",
|
|
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 for a specific error trace (requires a `traceId` from `get_latest_error`, `get_error_list`, or `get_trace`)",
|
|
295
|
-
"- `get_session_timeline` - Get the timeline of all traces in the current session",
|
|
296
|
-
"",
|
|
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`.",
|
|
298
|
-
""
|
|
299
|
-
].join("\n");
|
|
319
|
+
const content = buildAgentInstructionBody();
|
|
300
320
|
switch (agent.name) {
|
|
301
321
|
case "claude": {
|
|
302
322
|
const m = htmlMarkers(sdkVersion);
|
|
@@ -332,4 +352,4 @@ export {
|
|
|
332
352
|
generateMcpConfig,
|
|
333
353
|
generateInfoSection
|
|
334
354
|
};
|
|
335
|
-
//# sourceMappingURL=chunk-
|
|
355
|
+
//# sourceMappingURL=chunk-TJ46YOGJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agent-detection/detect.ts","../src/agent-detection/agent-instruction-text.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","/**\n * The text body the SDK injects into a user's agent-instruction file\n * (CLAUDE.md, .cursorrules, codex.md, etc.) between the\n * `<!-- glasstrace:mcp:start v=<sdkVersion> -->` ... `<!-- glasstrace:mcp:end -->`\n * managed-section markers.\n *\n * **Why this lives in its own module:** the text is the contract\n * between the SDK and the user's coding agent at runtime — what the\n * AI reads when it decides whether to call Glasstrace MCP and how to\n * use the returned evidence. It evolves on a different cadence from\n * the surrounding marker / version-stamp / per-agent-format\n * machinery in `configs.ts`. Keeping it in a sibling module means\n * future content edits are a single-file change and don't risk\n * disturbing the `configs.ts` rendering machinery (which carries the\n * SDK-050 / DISC-1592 / DISC-1602 marker contract that has soaked in\n * production and must not regress).\n *\n * **Vocabulary alignment:** every MCP tool name and response-field\n * name in the body below is verified against the current MCP server\n * contract maintained in the private `glasstrace-product` repo\n * (`shared/types/wire-mcp.ts` and `shared/types/agent-evidence.ts`\n * there); the SDK consumes the resulting wire format but does not\n * own the schema source of truth for those tool names and field\n * names. If the server-side MCP contract evolves (renames a field,\n * restructures `suggestedFollowups`, adds new tools, etc.), update\n * this module in lockstep with the protocol change so the\n * agent-instruction text never references fields that don't exist.\n *\n * **Heuristic-first vs tool-first framing:** the body opens with\n * explicit \"Call Glasstrace FIRST when\" / \"SKIP Glasstrace when\"\n * rules so a frontier agent has a cheap pre-tool-call decision\n * heuristic it can apply BEFORE spending tokens on tool\n * consideration. The Workflow section then names\n * `find_trace_candidates` as the entry point and instructs the\n * agent to READ `closeMatches` / `recentRoutesSample` /\n * `recoveryActions` before pivoting to source — that is the\n * load-bearing recovery contract from MCP-025 / MCP-027 (codified\n * in `wire-mcp.ts` `ToolDiagnosticSchema` and `CandidateDiagnosticSchema`)\n * and is the failure mode the prior SDK-050 cost-aware decision\n * paragraph did not surface.\n */\n\n/**\n * The full agent-instruction body, returned as a markdown string.\n *\n * The body has NO endpoint URL inlined — frontier agents reach\n * Glasstrace via the MCP server name `glasstrace` configured in the\n * user's MCP config (`.glasstrace/mcp.json` or per-agent native\n * config), not by reading a URL out of the instruction file. Keeping\n * the URL out of the instruction text avoids drift between the\n * instruction file and the MCP config and keeps the body tight.\n *\n * Returns the body WITHOUT the surrounding markers — the caller\n * (`generateInfoSection` in `configs.ts`) wraps the body with the\n * version-stamped start/end markers per the SDK-050 / DISC-1592\n * marker contract.\n */\nexport function buildAgentInstructionBody(): string {\n return [\n \"\",\n \"## Glasstrace MCP — Runtime Debugging Evidence\",\n \"\",\n \"Glasstrace is connected via MCP (`glasstrace`). It captures runtime traces from this app and exposes them through tools that disambiguate bugs source alone cannot resolve.\",\n \"\",\n \"### Call Glasstrace FIRST when:\",\n \"- A value passed at runtime is suspect: wrong role, locale, timezone, template, tenant id, or any enum/config that branches downstream.\",\n \"- The bug is in a side-effect operation: email sent, calendar event created, webhook dispatched, queued job, `after()` callback.\",\n \"- The user reports a symptom but you do not yet know which code path actually executed.\",\n \"- You need to confirm a route or procedure ran in the relevant time window before doing a source dive.\",\n \"\",\n \"### SKIP Glasstrace when:\",\n \"- The bug is statically obvious from source (N+1 query, missing await, redundant query, type error, missing null check).\",\n \"- The change is a refactor whose correctness does not depend on runtime behavior.\",\n \"- You already have a precise traceId from another source.\",\n \"\",\n \"### Workflow\",\n \"1. Start with `find_trace_candidates`. Pass whatever route or procedure name is natural — the server normalizes vocabulary and, on miss, returns close matches and a sample of routes actually present in the window.\",\n \"2. Take the highest-confidence candidate's `suggestedFollowups` and pass them straight to `get_trace` or `get_root_cause`.\",\n \"3. For side-effect bugs, read `sideEffectSummary` in the `get_trace` / `get_root_cause` response. The allowlisted fields (`templateKey`, `providerOperation`, `role`, `locale`, `timezone`, `status`, `phase`) are the ones that disambiguate payload bugs.\",\n \"4. If a tool returns empty, READ the response's `closeMatches`, `recentRoutesSample`, and `recoveryActions` before pivoting to source. Empty results carry `notAbsenceProof: true` — they are never proof the bug did not occur.\",\n \"\",\n \"### Tools\",\n \"- `find_trace_candidates` — discovery, vocabulary-tolerant filter\",\n \"- `get_trace` — exact trace by `traceId`\",\n \"- `get_root_cause` — root-cause analysis for a `traceId`\",\n \"- `get_session_timeline` — events for a session\",\n \"- `get_latest_error` / `get_error_list` — recent server errors\",\n \"\",\n \"Side-effect evidence is allowlisted and compact by design. Fields you don't see may have been omitted by policy, not absent at runtime.\",\n \"\",\n ].join(\"\\n\");\n}\n","import type { DetectedAgent } from \"./detect.js\";\nimport { buildAgentInstructionBody } from \"./agent-instruction-text.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 type: \"http\",\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 type: \"http\",\n url: 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 a\n * tight, agent-facing decision policy + workflow + tool list — no\n * endpoint URL, no auth tokens, no setup instructions (those live in\n * the user's MCP config and the SDK README; the agent reads this file\n * to decide WHEN to call Glasstrace MCP and HOW to use the returned\n * evidence).\n *\n * The rendered block opens with explicit \"Call Glasstrace FIRST when\"\n * / \"SKIP Glasstrace when\" decision rules so a frontier agent has a\n * cheap pre-tool-call heuristic it can apply BEFORE spending tokens\n * on tool consideration. The Workflow section names\n * `find_trace_candidates` as the discovery entry point and instructs\n * the agent to READ `closeMatches` / `recentRoutesSample` /\n * `recoveryActions` before pivoting to source — that is the\n * load-bearing recovery contract from MCP-025 / MCP-027 (codified\n * in the server-side MCP contract maintained in the private\n * `glasstrace-product` repo's `shared/types/wire-mcp.ts` —\n * `ToolDiagnosticSchema` / `CandidateDiagnosticSchema`) and it\n * prevents the bail-to-source failure mode that the prior SDK-050\n * cost-aware decision paragraph did not surface.\n *\n * The body itself lives in a sibling module\n * (`agent-instruction-text.ts`) so future content evolutions are a\n * single-file edit and don't disturb the marker / version-stamp /\n * per-agent-format machinery in this file.\n *\n * The start marker carries a `v=<sdkVersion>` stamp (DISC-1592 /\n * SDK-050) so a later `glasstrace upgrade-instructions` run — and\n * the SDK's stale-section warning at init — can detect that the\n * 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. (Validated for\n * non-emptiness here for backwards compatibility with the prior\n * SDK-050 contract; not currently inlined in the body — agents\n * reach Glasstrace via the MCP server name `glasstrace` configured\n * separately in `.glasstrace/mcp.json` or per-agent native config.)\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 const content = buildAgentInstructionBody();\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"]}
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
isDevApiKey,
|
|
6
6
|
readEnvLocalApiKey,
|
|
7
7
|
writeAndFsyncTempSync
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RL43PU2X.js";
|
|
9
9
|
import {
|
|
10
10
|
AnonApiKeySchema
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-6RKS3DNA.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-UMGZJYC4.js.map
|