@glasstrace/sdk 1.10.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -5
- package/dist/{chunk-WQF7ZQOM.js → chunk-DQFGNX3H.js} +13 -8
- package/dist/{chunk-WQF7ZQOM.js.map → chunk-DQFGNX3H.js.map} +1 -1
- package/dist/{chunk-UMGZJYC4.js → chunk-FQ4SEG6Y.js} +8 -3
- package/dist/chunk-FQ4SEG6Y.js.map +1 -0
- package/dist/chunk-KOYZJN6G.js +651 -0
- package/dist/chunk-KOYZJN6G.js.map +1 -0
- package/dist/{chunk-ZBQQXVHD.js → chunk-YIEXKQYP.js} +2 -67
- package/dist/chunk-YIEXKQYP.js.map +1 -0
- package/dist/cli/init.cjs +460 -127
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +29 -16
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +346 -98
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +32 -14
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/status.cjs +6 -1
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.js +7 -2
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/uninit.cjs +6 -1
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.js +2 -2
- package/dist/cli/upgrade-instructions.cjs +390 -113
- package/dist/cli/upgrade-instructions.cjs.map +1 -1
- package/dist/cli/upgrade-instructions.js +70 -18
- package/dist/cli/upgrade-instructions.js.map +1 -1
- package/dist/index.cjs +11 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/node-entry.cjs +11 -6
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-TJ46YOGJ.js +0 -355
- package/dist/chunk-TJ46YOGJ.js.map +0 -1
- package/dist/chunk-UMGZJYC4.js.map +0 -1
- package/dist/chunk-ZBQQXVHD.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent-detection/inject.ts"],"sourcesContent":["import { chmod, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport type { DetectedAgent } from \"./detect.js\";\n\n/**\n * HTML start-marker regex used in markdown files (.md). Matches both\n * legacy unstamped markers (pre-SDK-050) and stamped markers (SDK-050+).\n *\n * Two shapes:\n * - Legacy: `<!-- glasstrace:mcp:start -->`\n * - Stamped: `<!-- glasstrace:mcp:start v=1.4.0 -->`\n *\n * The optional `v=<semver>` capture group is the SDK-050 version stamp\n * (DISC-1592 Required Semantics Item 1). Recognising the legacy form is\n * load-bearing for the SDK-050 backward-compatibility constraint: an\n * upgrading user's first re-render must replace the existing block in\n * place rather than appending a duplicate. Subsequent re-renders write\n * the stamped form.\n *\n * The stamp character class\n * `[^\\s>]+` deliberately excludes whitespace and `>` so a hand-edited\n * malformed marker cannot terminate the comment early or smuggle a\n * line break into the file. The end marker (`...mcp:end`) is unstamped.\n */\nconst HTML_START_RE =\n /^<!--\\s*glasstrace:mcp:start(?:\\s+v=([^\\s>]+))?\\s*-->$/;\nconst HTML_END = \"<!-- glasstrace:mcp:end -->\";\n\n/**\n * Hash-prefixed start-marker regex used in plain text files (e.g.\n * `.cursorrules`). Same legacy/stamped shape model as the HTML form,\n * with the constraint that the captured stamp is non-whitespace\n * (`\\S+`) — the line ends at end-of-line, so there is no closing\n * delimiter to escape.\n */\nconst HASH_START_RE = /^#\\s*glasstrace:mcp:start(?:\\s+v=(\\S+))?$/;\nconst HASH_END = \"# glasstrace:mcp:end\";\n\n/**\n * Parsed start marker — its kind (HTML vs hash) and, when present, the\n * `v=<sdkVersion>` stamp. `stamp === null` means the marker matched the\n * legacy unstamped form (pre-SDK-050).\n */\nexport interface ParsedStartMarker {\n kind: \"html\" | \"hash\";\n stamp: string | null;\n}\n\n/**\n * Parses a single line as a Glasstrace start marker.\n *\n * Accepts both legacy unstamped markers (pre-SDK-050) and stamped\n * markers (SDK-050+). Returns `null` if the line is not a start\n * marker. Trims whitespace before matching so leading/trailing spaces\n * in user-edited files do not defeat detection.\n *\n * Exported so the upgrade-notice module (which checks the start\n * marker line directly) can share the regex, keeping a single source\n * of truth for the marker shape.\n */\nexport function parseStartMarkerLine(\n line: string,\n): ParsedStartMarker | null {\n const trimmed = line.trim();\n const html = HTML_START_RE.exec(trimmed);\n if (html !== null) {\n return { kind: \"html\", stamp: html[1] ?? null };\n }\n const hash = HASH_START_RE.exec(trimmed);\n if (hash !== null) {\n return { kind: \"hash\", stamp: hash[1] ?? null };\n }\n return null;\n}\n\nfunction isEndMarker(line: string): boolean {\n const trimmed = line.trim();\n return trimmed === HTML_END || trimmed === HASH_END;\n}\n\n/**\n * Public alias for {@link isEndMarker}, used by the upgrade-notice\n * module to confirm that a stamped start marker has a matching end\n * before classifying the file as having a managed section. Exported\n * only for cross-module reuse within `agent-detection/`; not part of\n * the public SDK surface.\n */\nexport function isEndMarkerLine(line: string): boolean {\n return isEndMarker(line);\n}\n\n/**\n * Determines whether an error is a filesystem permission or read-only error.\n * Covers EACCES (permission denied), EPERM (operation not permitted), and\n * EROFS (read-only filesystem) to handle containerized/mounted environments.\n */\nfunction isPermissionError(err: unknown): boolean {\n const code = (err as NodeJS.ErrnoException).code;\n return code === \"EACCES\" || code === \"EPERM\" || code === \"EROFS\";\n}\n\n/**\n * Writes MCP configuration content to an agent's config file path.\n *\n * Creates parent directories as needed and sets file permissions to 0o600\n * (owner read/write only) since config files may contain auth tokens.\n *\n * Fails gracefully: logs a warning to stderr on permission errors instead\n * of throwing.\n *\n * @param agent - The detected agent whose config path to write to.\n * @param content - The full configuration file content.\n * @param projectRoot - The project root (reserved for future use).\n */\nexport async function writeMcpConfig(\n agent: DetectedAgent,\n content: string,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n projectRoot: string,\n): Promise<void> {\n if (agent.mcpConfigPath === null) {\n return;\n }\n\n const configPath = agent.mcpConfigPath;\n const parentDir = dirname(configPath);\n\n try {\n await mkdir(parentDir, { recursive: true });\n } catch (err: unknown) {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot create directory ${parentDir}: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n\n try {\n await writeFile(configPath, content, { mode: 0o600 });\n } catch (err: unknown) {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot write config file ${configPath}: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n\n // Ensure permissions are set even if the file already existed\n // (writeFile mode only applies to newly created files on some platforms)\n try {\n await chmod(configPath, 0o600);\n } catch {\n // Best-effort; the writeFile mode should have handled this\n }\n}\n\n/**\n * Finds existing marker boundaries in file content.\n *\n * Recognises both the legacy unstamped marker form (pre-SDK-050) and\n * the stamped form (SDK-050+) for both HTML-comment and hash-prefix\n * conventions. Returns the start and end line indices, or `null` if no\n * complete marker pair is found. The `v=<sdkVersion>` stamp itself is\n * only inspected by the upgrade-notice module via\n * {@link parseStartMarkerLine}; in-place replacement only needs the\n * line indices.\n *\n * When multiple start markers appear before the first end marker\n * (e.g. a quoted example of the marker shape earlier in the file\n * followed by the real managed block), the boundary anchors to the\n * MOST RECENT start preceding the end. This matches the pre-SDK-050\n * behaviour of `findMarkerBoundaries` and avoids the \"swallow the\n * user's example into the replacement\" failure mode that anchoring\n * to the FIRST start would produce.\n */\nfunction findMarkerBoundaries(\n lines: string[],\n): { startIdx: number; endIdx: number } | null {\n let startIdx = -1;\n\n for (let i = 0; i < lines.length; i++) {\n if (parseStartMarkerLine(lines[i]) !== null) {\n // Track the most recent start so a quoted/example marker earlier\n // in the file does not capture the replacement window.\n startIdx = i;\n } else if (startIdx !== -1 && isEndMarker(lines[i])) {\n return { startIdx, endIdx: i };\n }\n }\n\n return null;\n}\n\n/**\n * Injects an informational section into an agent's instruction file.\n *\n * Uses marker comments to enable idempotent updates:\n * - If the file contains marker pairs, replaces content between them.\n * - If the file exists but has no markers, appends the section.\n * - If the file does not exist, creates it with the section content.\n *\n * The boundary detector recognises both legacy unstamped markers\n * (pre-SDK-050) and stamped markers, so an upgrading user's first\n * re-render replaces the existing block in place rather than\n * appending a duplicate (DISC-1592 / SDK-050 backward-compatibility\n * constraint). Subsequent re-renders write the stamped form.\n *\n * Fails gracefully: logs a warning to stderr on read-only files instead\n * of throwing.\n *\n * @param agent - The detected agent whose info file to update.\n * @param content - The section content (including markers).\n * @param projectRoot - The project root (reserved for future use).\n */\nexport async function injectInfoSection(\n agent: DetectedAgent,\n content: string,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n projectRoot: string,\n): Promise<void> {\n if (agent.infoFilePath === null) {\n return;\n }\n\n // Empty content means nothing to inject (e.g., agents without info sections)\n if (content === \"\") {\n return;\n }\n\n const filePath = agent.infoFilePath;\n\n let existingContent: string | null = null;\n try {\n existingContent = await readFile(filePath, \"utf-8\");\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot read info file ${filePath}: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n }\n\n // File does not exist — create with section content\n if (existingContent === null) {\n try {\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, content, \"utf-8\");\n } catch (err: unknown) {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot write info file ${filePath}: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n return;\n }\n\n // File exists — check for markers\n const lines = existingContent.split(\"\\n\");\n const boundaries = findMarkerBoundaries(lines);\n\n let newContent: string;\n if (boundaries !== null) {\n // Replace everything from start marker through end marker (inclusive)\n const before = lines.slice(0, boundaries.startIdx);\n const after = lines.slice(boundaries.endIdx + 1);\n // content already includes markers and trailing newline\n const contentWithoutTrailingNewline = content.endsWith(\"\\n\")\n ? content.slice(0, -1)\n : content;\n newContent = [...before, contentWithoutTrailingNewline, ...after].join(\"\\n\");\n } else {\n // No markers found — append with a blank line separator\n const separator = existingContent.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n newContent = existingContent + separator + content;\n }\n\n try {\n await writeFile(filePath, newContent, \"utf-8\");\n } catch (err: unknown) {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot write info file ${filePath}: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n}\n\n/**\n * Returns true when the file at `filePath` contains a complete\n * Glasstrace managed section (marker pair). Matches both legacy\n * unstamped markers and SDK-050+ stamped markers. Used by the\n * upgrade-instructions CLI to decide which detected agent files\n * actually have a managed section to refresh.\n *\n * Returns `false` for the genuine \"file does not exist\" case\n * (`ENOENT`). Any other read error — permission denied (`EACCES`),\n * not-permitted (`EPERM`), read-only (`EROFS`), I/O error, etc. — is\n * re-thrown so the caller can surface it to the user. Swallowing\n * those would let `upgrade-instructions` report an inaccessible file\n * as \"skipped (no managed section present)\" and silently mask a real\n * permission problem (Codex review on PR #247).\n */\nexport async function hasManagedSection(filePath: string): Promise<boolean> {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return false;\n throw err;\n }\n return findMarkerBoundaries(content.split(\"\\n\")) !== null;\n}\n\n/**\n * Ensures that the given paths are listed in the project's `.gitignore`.\n *\n * Only adds entries for paths that are not already present. Creates the\n * `.gitignore` file if it does not exist. Skips absolute paths (e.g.,\n * Windsurf's global config) since those are outside the project tree.\n *\n * Fails gracefully: logs a warning to stderr on permission errors.\n *\n * @param paths - Relative paths to ensure are gitignored.\n * @param projectRoot - The project root directory.\n */\nexport async function updateGitignore(\n paths: string[],\n projectRoot: string,\n): Promise<void> {\n const gitignorePath = join(projectRoot, \".gitignore\");\n\n // Filter out absolute paths — they reference locations outside the project\n // Uses isAbsolute() to handle both POSIX and Windows path formats\n const relativePaths = paths.filter((p) => !isAbsolute(p));\n\n if (relativePaths.length === 0) {\n return;\n }\n\n let existingContent = \"\";\n try {\n existingContent = await readFile(gitignorePath, \"utf-8\");\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot read .gitignore: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n }\n\n // Parse existing entries, trimming whitespace for comparison\n const existingLines = existingContent\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\");\n\n const existingSet = new Set(existingLines);\n\n // Normalize entries: trim whitespace, convert backslashes to forward slashes\n // (git ignore patterns use / as separator; backslash is an escape character),\n // drop empties, and deduplicate against existing entries.\n const toAdd = relativePaths\n .map((p) => p.trim().replace(/\\\\/g, \"/\"))\n .filter((p) => p !== \"\" && !existingSet.has(p));\n\n if (toAdd.length === 0) {\n return;\n }\n\n // Ensure file ends with newline before appending\n let updatedContent = existingContent;\n if (updatedContent.length > 0 && !updatedContent.endsWith(\"\\n\")) {\n updatedContent += \"\\n\";\n }\n\n updatedContent += toAdd.join(\"\\n\") + \"\\n\";\n\n try {\n await writeFile(gitignorePath, updatedContent, \"utf-8\");\n } catch (err: unknown) {\n if (isPermissionError(err)) {\n process.stderr.write(\n `Warning: cannot write .gitignore: permission denied\\n`,\n );\n return;\n }\n throw err;\n }\n}\n"],"mappings":"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","names":[]}
|