@neurynae/toolcairn-mcp 0.10.0 → 0.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/index.js +849 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/esm_shims.js","../../../packages/config/src/index.ts","../../../packages/errors/src/error-codes.ts","../../../packages/errors/src/errors.ts","../../../packages/errors/src/serializers.ts","../../../packages/errors/src/logger.ts","../../../packages/errors/src/mcp-error-wrapper.ts","../../../packages/errors/src/index.ts","../src/index.prod.ts","../../../packages/remote/src/index.ts","../../../packages/remote/src/client.ts","../../../packages/remote/src/credentials.ts","../../../packages/remote/src/device-auth.ts","../src/project-setup.ts","../src/tools/generate-tracker.ts","../src/server.prod.ts","../../../packages/tools-local/src/index.ts","../../../packages/tools-local/src/schemas.ts","../../../packages/tools-local/src/utils.ts","../../../packages/tools-local/src/handlers/classify-prompt.ts","../../../packages/tools-local/src/handlers/toolcairn-init.ts","../../../packages/tools-local/src/config-store/index.ts","../../../packages/tools-local/src/config-store/paths.ts","../../../packages/tools-local/src/config-store/read.ts","../../../packages/tools-local/src/discovery/util/fs.ts","../../../packages/tools-local/src/config-store/write.ts","../../../packages/tools-local/src/config-store/audit.ts","../../../packages/tools-local/src/config-store/migrate.ts","../../../packages/tools-local/src/config-store/mutate.ts","../../../packages/tools-local/src/config-store/skeleton.ts","../../../packages/tools-local/src/discovery/index.ts","../../../packages/tools-local/src/discovery/scan-project.ts","../../../packages/tools-local/src/discovery/ecosystem-detect.ts","../../../packages/tools-local/src/discovery/frameworks/detect.ts","../../../packages/tools-local/src/discovery/language-detect.ts","../../../packages/tools-local/src/discovery/parsers/index.ts","../../../packages/tools-local/src/discovery/parsers/cargo.ts","../../../packages/tools-local/src/discovery/parsers/composer.ts","../../../packages/tools-local/src/discovery/parsers/dart.ts","../../../packages/tools-local/src/discovery/parsers/dotnet.ts","../../../packages/tools-local/src/discovery/parsers/go.ts","../../../packages/tools-local/src/discovery/parsers/gradle.ts","../../../packages/tools-local/src/discovery/parsers/maven.ts","../../../packages/tools-local/src/discovery/parsers/mix.ts","../../../packages/tools-local/src/discovery/parsers/npm.ts","../../../packages/tools-local/src/discovery/parsers/pypi.ts","../../../packages/tools-local/src/discovery/parsers/ruby.ts","../../../packages/tools-local/src/discovery/parsers/swift.ts","../../../packages/tools-local/src/discovery/workspaces/glob.ts","../../../packages/tools-local/src/discovery/workspaces/walker.ts","../../../packages/tools-local/src/templates/agent-instructions.ts","../../../packages/tools-local/src/handlers/read-project-config.ts","../../../packages/tools-local/src/handlers/update-project-config.ts","../src/middleware/event-logger.ts","../src/transport.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { z } from 'zod';\n\nconst configSchema = z.object({\n // ── MCP Server ────────────────────────────────────────────────────────────\n MCP_SERVER_PORT: z.coerce.number().int().positive().default(3001),\n MCP_SERVER_HOST: z.string().default('0.0.0.0'),\n\n // ── Deployment Mode ───────────────────────────────────────────────────────\n /** dev: direct Docker DB connections | production: HTTP client to remote API */\n TOOLPILOT_MODE: z.enum(['dev', 'staging', 'production']).default('dev'),\n /** URL of the ToolCairn HTTP API (used when TOOLPILOT_MODE=production) */\n TOOLPILOT_API_URL: z.string().default('https://api.neurynae.com'),\n\n // ── General ───────────────────────────────────────────────────────────────\n NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n});\n\nexport type Config = z.infer<typeof configSchema>;\n\nfunction loadConfig(): Config {\n const result = configSchema.safeParse(process.env);\n if (!result.success) {\n console.error('❌ Invalid environment configuration:');\n console.error(result.error.format());\n process.exit(1);\n }\n return result.data;\n}\n\n/** Validated, typed configuration loaded from environment variables. */\nexport const config: Config = loadConfig();\n","/**\n * Canonical error code catalog.\n * All AppError subclasses set one of these codes.\n * Codes are stable string constants — safe to log, persist, and return to clients.\n */\nexport const ErrorCode = {\n // ── Database ────────────────────────────────────────────────────────────────\n ERR_DB_CONNECTION: 'ERR_DB_CONNECTION',\n ERR_DB_QUERY: 'ERR_DB_QUERY',\n ERR_DB_TIMEOUT: 'ERR_DB_TIMEOUT',\n ERR_DB_CONSTRAINT: 'ERR_DB_CONSTRAINT',\n ERR_DB_NOT_FOUND: 'ERR_DB_NOT_FOUND',\n\n // ── Validation ──────────────────────────────────────────────────────────────\n ERR_VALIDATION_INPUT: 'ERR_VALIDATION_INPUT',\n ERR_VALIDATION_SCHEMA: 'ERR_VALIDATION_SCHEMA',\n\n // ── Auth ────────────────────────────────────────────────────────────────────\n ERR_AUTH_TOKEN_EXPIRED: 'ERR_AUTH_TOKEN_EXPIRED',\n ERR_AUTH_UNAUTHORIZED: 'ERR_AUTH_UNAUTHORIZED',\n ERR_AUTH_FORBIDDEN: 'ERR_AUTH_FORBIDDEN',\n\n // ── External services ───────────────────────────────────────────────────────\n ERR_EXTERNAL_GITHUB: 'ERR_EXTERNAL_GITHUB',\n ERR_EXTERNAL_NOMIC: 'ERR_EXTERNAL_NOMIC',\n ERR_EXTERNAL_QDRANT: 'ERR_EXTERNAL_QDRANT',\n ERR_EXTERNAL_MEMGRAPH: 'ERR_EXTERNAL_MEMGRAPH',\n ERR_EXTERNAL_RAZORPAY: 'ERR_EXTERNAL_RAZORPAY',\n\n // ── Queue ───────────────────────────────────────────────────────────────────\n ERR_QUEUE_PUBLISH: 'ERR_QUEUE_PUBLISH',\n ERR_QUEUE_CONSUME: 'ERR_QUEUE_CONSUME',\n ERR_QUEUE_TIMEOUT: 'ERR_QUEUE_TIMEOUT',\n\n // ── Search ──────────────────────────────────────────────────────────────────\n ERR_SEARCH_PIPELINE: 'ERR_SEARCH_PIPELINE',\n ERR_SEARCH_EMBEDDING: 'ERR_SEARCH_EMBEDDING',\n ERR_SEARCH_NO_RESULTS: 'ERR_SEARCH_NO_RESULTS',\n\n // ── Indexer ─────────────────────────────────────────────────────────────────\n ERR_INDEXER_CRAWL: 'ERR_INDEXER_CRAWL',\n ERR_INDEXER_PROCESS: 'ERR_INDEXER_PROCESS',\n ERR_INDEXER_WRITE: 'ERR_INDEXER_WRITE',\n\n // ── Network ─────────────────────────────────────────────────────────────────\n ERR_NETWORK_TIMEOUT: 'ERR_NETWORK_TIMEOUT',\n ERR_NETWORK_UNREACHABLE: 'ERR_NETWORK_UNREACHABLE',\n\n // ── MCP ─────────────────────────────────────────────────────────────────────\n ERR_MCP_HANDLER: 'ERR_MCP_HANDLER',\n ERR_MCP_AUTH: 'ERR_MCP_AUTH',\n\n // ── Generic ─────────────────────────────────────────────────────────────────\n ERR_INTERNAL: 'ERR_INTERNAL',\n ERR_NOT_FOUND: 'ERR_NOT_FOUND',\n ERR_RATE_LIMIT: 'ERR_RATE_LIMIT',\n} as const;\n\nexport type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode];\n","import { ErrorCode, type ErrorCodeValue } from './error-codes.js';\nimport type { ErrorContext, Severity } from './types.js';\n\nexport interface AppErrorOptions {\n code: ErrorCodeValue;\n message: string;\n /** HTTP status code to return to the client. Default: 500 */\n httpStatus?: number;\n /** How severe is this error for alerting/triage. Default: 'medium' */\n severity?: Severity;\n /**\n * Operational errors are expected conditions (validation failure, rate limit,\n * not found). Their message is safe to expose to clients.\n *\n * Non-operational errors are programmer bugs (null reference, type error).\n * Their message must be masked — only a generic \"internal error\" reaches clients.\n *\n * Default: true\n */\n isOperational?: boolean;\n /** The underlying error that caused this one — preserves the full chain */\n cause?: unknown;\n /** Structured context: module, operation, IDs — logged alongside the error */\n context?: ErrorContext;\n}\n\n/**\n * Base application error. All domain errors extend this.\n *\n * Carries structured metadata for:\n * - Deterministic error codes (safe to log, persist, return to clients)\n * - Severity-based alerting\n * - Operational vs programmer error distinction\n * - Rich context for debugging (module, operation, IDs)\n * - Full cause chain via Error.cause (ES2022)\n */\nexport class AppError extends Error {\n public readonly code: ErrorCodeValue;\n public readonly httpStatus: number;\n public readonly severity: Severity;\n public readonly isOperational: boolean;\n public readonly context: ErrorContext;\n public readonly timestamp: string;\n\n constructor(opts: AppErrorOptions) {\n super(opts.message, { cause: opts.cause });\n this.name = this.constructor.name;\n this.code = opts.code;\n this.httpStatus = opts.httpStatus ?? 500;\n this.severity = opts.severity ?? 'medium';\n this.isOperational = opts.isOperational ?? true;\n this.context = opts.context ?? {};\n this.timestamp = new Date().toISOString();\n\n // Restore correct prototype chain — required for `instanceof` checks to\n // work correctly when compiling to CommonJS with TypeScript.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** Structured JSON representation used by the pino error serializer */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n httpStatus: this.httpStatus,\n severity: this.severity,\n isOperational: this.isOperational,\n context: this.context,\n timestamp: this.timestamp,\n stack: this.stack,\n cause:\n this.cause instanceof Error\n ? { name: this.cause.name, message: this.cause.message, stack: this.cause.stack }\n : this.cause,\n };\n }\n}\n\n// ── Domain error classes ──────────────────────────────────────────────────────\n// Each sets sensible defaults so call sites stay concise.\n\nexport class DatabaseError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_DB_QUERY,\n message: opts.message,\n httpStatus: 503,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class NetworkError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_NETWORK_TIMEOUT,\n message: opts.message,\n httpStatus: 502,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class ValidationError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_VALIDATION_INPUT,\n message: opts.message,\n httpStatus: 400,\n severity: 'low',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class AuthError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_AUTH_UNAUTHORIZED,\n message: opts.message,\n httpStatus: 401,\n severity: 'medium',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class ExternalServiceError extends AppError {\n constructor(opts: {\n service: string;\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_INTERNAL,\n message: `[${opts.service}] ${opts.message}`,\n httpStatus: 502,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: { ...opts.context, service: opts.service },\n });\n }\n}\n\nexport class QueueError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_QUEUE_PUBLISH,\n message: opts.message,\n httpStatus: 503,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class SearchError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_SEARCH_PIPELINE,\n message: opts.message,\n httpStatus: 500,\n severity: 'medium',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class IndexerError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_INDEXER_PROCESS,\n message: opts.message,\n httpStatus: 500,\n severity: 'medium',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class VectorError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_EXTERNAL_NOMIC,\n message: opts.message,\n httpStatus: 502,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n","import { AppError } from './errors.js';\n\n/**\n * Custom pino error serializer.\n *\n * When pino logs an object with an `err` or `error` field, it runs it through\n * this serializer. AppError instances get full structured metadata extracted.\n * Plain Error instances get standard fields. Non-Error values are stringified.\n *\n * Usage in logger options:\n * serializers: { err: errorSerializer, error: errorSerializer }\n */\nexport function errorSerializer(err: unknown): Record<string, unknown> {\n if (err instanceof AppError) {\n return err.toJSON();\n }\n\n if (err instanceof Error) {\n return {\n name: err.name,\n message: err.message,\n stack: err.stack,\n cause:\n err.cause instanceof Error\n ? { name: err.cause.name, message: err.cause.message, stack: err.cause.stack }\n : err.cause,\n };\n }\n\n return { message: String(err) };\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport pino, { type Logger, type LoggerOptions } from 'pino';\nimport { errorSerializer } from './serializers.js';\n\nconst REDACT_PATHS = [\n 'password',\n 'token',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n 'apiKey',\n 'api_key',\n 'secret',\n 'TOOLPILOT_API_KEY',\n 'authorization',\n 'cookie',\n '*.password',\n '*.token',\n '*.secret',\n '*.apiKey',\n '*.api_key',\n];\n\nexport interface CreateLoggerOptions {\n /** Module name used in every log line, e.g. '@toolcairn/mcp-server' */\n name: string;\n /** Override the environment-driven log level */\n level?: string;\n /** Additional fields merged into every log line's base object */\n defaultFields?: Record<string, unknown>;\n}\n\n/**\n * Creates a pino logger for use inside the MCP server.\n *\n * IMPORTANT: The MCP JSON-RPC protocol communicates over stdout.\n * All logging MUST go to stderr (fd=2) to avoid corrupting the protocol stream.\n *\n * In production the logger writes to two targets:\n * 1. stderr — all messages at the configured level (visible via `npx toolcairn-mcp 2>/dev/null`)\n * 2. ~/.toolcairn/logs/mcp-error-YYYY-MM-DD.log — warn+ messages for post-hoc debugging\n *\n * In development (NODE_ENV !== 'production') the file transport is omitted to\n * avoid cluttering the user's home directory during testing.\n */\nexport function createMcpLogger(opts: CreateLoggerOptions): Logger {\n const level =\n opts.level ??\n process.env.LOG_LEVEL ??\n (process.env.NODE_ENV !== 'production' ? 'debug' : 'info');\n\n const pinoOpts: LoggerOptions = {\n name: opts.name,\n level,\n serializers: {\n err: errorSerializer,\n error: errorSerializer,\n },\n redact: {\n paths: REDACT_PATHS,\n censor: '[REDACTED]',\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n base: {\n pid: process.pid,\n ...opts.defaultFields,\n },\n };\n\n const isProd = process.env.NODE_ENV === 'production';\n\n if (!isProd) {\n // Dev: stderr only, no file pollution\n return pino({ ...pinoOpts, transport: { target: 'pino/file', options: { destination: 2 } } });\n }\n\n // Production: stderr + persistent error log file\n const logDir = join(homedir(), '.toolcairn', 'logs');\n const today = new Date().toISOString().slice(0, 10);\n const errorLogPath = join(logDir, `mcp-error-${today}.log`);\n\n const transport = pino.transport({\n targets: [\n { target: 'pino/file', options: { destination: 2 }, level },\n { target: 'pino/file', options: { destination: errorLogPath, mkdir: true }, level: 'warn' },\n ],\n });\n\n return pino(pinoOpts, transport);\n}\n\n/** Alias for convenience — use createMcpLogger as the standard factory in MCP packages */\nexport { createMcpLogger as createLogger };\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { Logger } from 'pino';\nimport { ErrorCode } from './error-codes.js';\nimport { AppError } from './errors.js';\n\n/**\n * Wraps an MCP tool handler with structured error handling.\n *\n * Without this wrapper, an uncaught throw inside a tool handler crashes the\n * entire MCP server session. With it:\n * - AppError instances are caught, logged at appropriate severity, and returned\n * as a proper MCP CallToolResult with isError=true\n * - Unknown errors are caught, logged at 'error', and returned with a generic\n * ERR_MCP_HANDLER code\n *\n * The handler itself is responsible for returning CallToolResult on expected\n * failures (validation, not-found). This wrapper is a safety net for unexpected\n * exceptions that escape normal control flow.\n *\n * Compose with withEventLogging from event-logger.ts — this wrapper goes INSIDE\n * the event logger so errors are both logged and recorded as events:\n *\n * withEventLogging('search_tools', withErrorHandling('search_tools', logger, handler))\n */\nexport function withErrorHandling<TArgs>(\n toolName: string,\n logger: Logger,\n handler: (args: TArgs) => Promise<CallToolResult>,\n): (args: TArgs) => Promise<CallToolResult> {\n return async (args: TArgs): Promise<CallToolResult> => {\n try {\n return await handler(args);\n } catch (err) {\n if (err instanceof AppError) {\n const logLevel = err.severity === 'critical' || err.severity === 'high' ? 'error' : 'warn';\n\n logger[logLevel]({ err, tool: toolName }, `Tool ${toolName} failed: ${err.message}`);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n ok: false,\n error: err.code,\n message: err.isOperational ? err.message : 'An internal error occurred',\n }),\n },\n ],\n isError: true,\n };\n }\n\n // Unknown/programmer error\n logger.error({ err, tool: toolName }, `Unexpected error in tool ${toolName}`);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n ok: false,\n error: ErrorCode.ERR_MCP_HANDLER,\n message: err instanceof Error ? err.message : String(err),\n }),\n },\n ],\n isError: true,\n };\n }\n };\n}\n","export { ErrorCode, type ErrorCodeValue } from './error-codes.js';\nexport type { ErrorContext, Severity } from './types.js';\nexport {\n AppError,\n type AppErrorOptions,\n DatabaseError,\n NetworkError,\n ValidationError,\n AuthError,\n ExternalServiceError,\n QueueError,\n SearchError,\n IndexerError,\n VectorError,\n} from './errors.js';\nexport { errorSerializer } from './serializers.js';\nexport { createMcpLogger, createLogger, type CreateLoggerOptions } from './logger.js';\nexport { withErrorHandling } from './mcp-error-wrapper.js';\n","/**\n * Production-only entry point for the published npm bundle.\n *\n * Auth flow (automatic, survives restarts, no reconnect needed):\n * - Valid token → buildProdServer() — all 14 tools immediately\n * - No token, pending-auth.json exists (previous process was killed mid-poll):\n * → Resume polling; browser already open — don't open again\n * - No token, no pending auth:\n * → Request new device code, persist to pending-auth.json\n * → Open browser, show URL + code in instructions\n * → Poll in background; when confirmed: dynamically add all 14 tools\n * to the running server (notifications/tools/list_changed sent to client)\n * → No reconnect required\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { config } from '@toolcairn/config';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport {\n isTokenValid,\n loadCredentials,\n loadPendingAuth,\n requestDeviceCode,\n startDeviceAuth,\n} from '@toolcairn/remote';\nimport { z } from 'zod';\nimport { ensureProjectSetup } from './project-setup.js';\nimport { addToolsToServer, buildProdServer } from './server.prod.js';\nimport { createTransport } from './transport.js';\n\nprocess.env.TOOLPILOT_MODE = 'production';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server' });\n\nasync function main(): Promise<void> {\n await ensureProjectSetup();\n\n const creds = await loadCredentials();\n const authenticated = creds !== null && isTokenValid(creds);\n\n let server: McpServer;\n\n if (authenticated) {\n logger.info({ user: creds.user_email }, 'Authenticated — starting full server');\n server = await buildProdServer();\n } else {\n let verificationUri = 'https://toolcairn.neurynae.com/signup';\n let userCode = '';\n\n try {\n const pending = await loadPendingAuth();\n if (pending) {\n // Resume from previous process — browser already open, just poll\n verificationUri = pending.verification_uri;\n userCode = pending.user_code;\n logger.info({ userCode }, 'Resuming pending sign-in');\n } else {\n // Fresh start — request new device code + open browser\n const codeData = await requestDeviceCode(config.TOOLPILOT_API_URL);\n verificationUri = codeData.verification_uri;\n userCode = codeData.user_code;\n logger.info({ userCode }, 'New sign-in started');\n }\n } catch (err) {\n logger.error({ err }, 'Could not reach ToolCairn API — check your connection');\n }\n\n const instructions = userCode\n ? `# ToolCairn — Sign In Required\\n\\nA browser window should have opened automatically.\\n\\n**Sign-in URL:** ${verificationUri}\\n**Code to confirm:** \\`${userCode}\\`\\n\\nOpen the URL, sign in, and confirm the code shown. All 14 tools will appear automatically — no restart needed.`\n : '# ToolCairn — Sign In Required\\n\\nVisit https://toolcairn.neurynae.com to create an account, then reconnect.';\n\n server = new McpServer({ name: 'toolcairn', version: '0.1.0' }, { instructions });\n\n server.registerTool(\n 'toolcairn_auth',\n {\n description: 'Check ToolCairn sign-in status.',\n inputSchema: z.object({ action: z.enum(['status']) }),\n },\n async () => ({\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n authenticated: false,\n sign_in_url: verificationUri,\n code: userCode || null,\n message: userCode\n ? `Open ${verificationUri} and confirm code \"${userCode}\". Tools will appear automatically when confirmed.`\n : 'Visit toolcairn.neurynae.com to sign up.',\n }),\n },\n ],\n }),\n );\n\n // Start auth flow in background.\n // On success: dynamically register all 14 tools on this same server.\n // The MCP SDK sends notifications/tools/list_changed — client refreshes\n // the tool list automatically, no reconnect required.\n startDeviceAuth(config.TOOLPILOT_API_URL)\n .then(async () => {\n logger.info('Sign-in complete — adding all tools to running server');\n try {\n await addToolsToServer(server);\n logger.info('All ToolCairn tools now available');\n } catch (err) {\n logger.error({ err }, 'Failed to add tools after sign-in — please reconnect');\n }\n })\n .catch((err: unknown) => {\n logger.error({ err }, 'Sign-in failed — please try again');\n });\n }\n\n const transport = createTransport();\n await server.connect(transport);\n logger.info(authenticated ? 'ToolCairn MCP ready' : 'ToolCairn MCP ready (awaiting sign-in)');\n}\n\nmain().catch((error: unknown) => {\n createMcpLogger({ name: '@toolcairn/mcp-server' }).error(\n { err: error },\n 'Failed to start MCP server',\n );\n process.exit(1);\n});\n","export { ToolCairnClient } from './client.js';\nexport type { ToolCairnClientOptions } from './client.js';\nexport {\n loadCredentials,\n loadOrCreateCredentials,\n saveCredentials,\n getApiKey,\n upgradeToAuthenticated,\n clearAuthentication,\n isTokenValid,\n savePendingAuth,\n loadPendingAuth,\n clearPendingAuth,\n} from './credentials.js';\nexport type { Credentials, PendingAuth } from './credentials.js';\nexport { startDeviceAuth, requestDeviceCode } from './device-auth.js';\n","/**\n * ToolCairnClient — HTTP client used by the thin npm MCP package.\n *\n * Makes one POST request per remote tool call to the ToolCairn API\n * (sitting behind a Cloudflare Worker in production, or directly in dev).\n *\n * Returns CallToolResult so the MCP server can pass responses through unchanged.\n */\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { ErrorCode } from '@toolcairn/errors';\nimport type { DiscoveryWarning, Ecosystem, MatchMethod } from '@toolcairn/types';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface ToolCairnClientOptions {\n /** Base URL of the ToolCairn API, e.g. https://api.neurynae.com */\n baseUrl: string;\n /** Anonymous API key (UUID) sent in X-ToolCairn-Key header */\n apiKey: string;\n /** Optional JWT access token — sent as Authorization: Bearer when present */\n accessToken?: string;\n /** Request timeout in ms (default 30s) */\n timeoutMs?: number;\n}\n\nexport class ToolCairnClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeoutMs: number;\n\n private readonly accessToken?: string;\n\n constructor(opts: ToolCairnClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.apiKey = opts.apiKey;\n this.accessToken = opts.accessToken;\n this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n // ── Core Search ──────────────────────────────────────────────────────────\n\n async searchTools(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/search', args);\n }\n\n async searchToolsRespond(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/search/respond', args);\n }\n\n // ── Graph ────────────────────────────────────────────────────────────────\n\n async checkCompatibility(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/graph/compatibility', args);\n }\n\n async compareTools(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/graph/compare', args);\n }\n\n async getStack(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/graph/stack', args);\n }\n\n // ── Intelligence ─────────────────────────────────────────────────────────\n\n async refineRequirement(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/intelligence/refine', args);\n }\n\n async verifySuggestion(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/intelligence/verify', args);\n }\n\n async checkIssue(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/intelligence/issue', args);\n }\n\n // ── Tool resolution ──────────────────────────────────────────────────────\n\n /**\n * Classify a batch of (ecosystem, name) tuples against the ToolCairn graph.\n *\n * Used by the discovery pipeline inside `toolcairn_init` — NOT exposed as an\n * MCP tool to the agent. Returns typed data, not CallToolResult.\n *\n * Graceful degradation:\n * - HTTP 404 (endpoint not deployed yet): returns all inputs as unmatched,\n * with a warning.\n * - Network error / timeout: same.\n * - HTTP 200 but malformed body: logs a warning, returns unmatched.\n *\n * Caller (scan-project) uses the unmatched results to classify tools as\n * `source: \"non_oss\"` and still returns a valid scan.\n */\n async batchResolve(items: Array<{ name: string; ecosystem: Ecosystem }>): Promise<{\n results: Array<{\n input: { name: string; ecosystem: Ecosystem };\n matched: boolean;\n match_method: MatchMethod;\n tool?: { canonical_name: string; github_url: string; categories: string[] };\n }>;\n warnings: DiscoveryWarning[];\n methods: Map<string, MatchMethod>;\n githubUrls: Map<string, string>;\n }> {\n const warnings: DiscoveryWarning[] = [];\n const methods = new Map<string, MatchMethod>();\n const githubUrls = new Map<string, string>();\n\n if (items.length === 0) {\n return { results: [], warnings, methods, githubUrls };\n }\n\n try {\n const res = await this.rawPost('/v1/tools/batch-resolve', {\n api_version: '1',\n tools: items,\n });\n\n if (res.status === 404) {\n warnings.push({\n scope: 'batch-resolve',\n message:\n '/v1/tools/batch-resolve not deployed on this engine — falling back to offline classification (source: non_oss).',\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n\n if (!res.ok) {\n warnings.push({\n scope: 'batch-resolve',\n message: `batch-resolve returned HTTP ${res.status} — all tools marked as non_oss.`,\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n\n const body = (await res.json()) as {\n resolved?: Array<{\n input: { name: string; ecosystem: Ecosystem };\n matched?: boolean;\n match_method?: MatchMethod;\n tool?: { canonical_name: string; github_url: string; categories: string[] };\n }>;\n };\n if (!Array.isArray(body.resolved)) {\n warnings.push({\n scope: 'batch-resolve',\n message: 'batch-resolve returned unexpected body shape — falling back.',\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n\n const results: Array<{\n input: { name: string; ecosystem: Ecosystem };\n matched: boolean;\n match_method: MatchMethod;\n tool?: { canonical_name: string; github_url: string; categories: string[] };\n }> = [];\n for (const entry of body.resolved) {\n const method = entry.match_method ?? (entry.matched ? 'tool_name_exact' : 'none');\n const matched = entry.matched ?? method !== 'none';\n const key = `${entry.input.ecosystem}:${entry.input.name}`;\n methods.set(key, method);\n if (entry.tool?.github_url) githubUrls.set(key, entry.tool.github_url);\n results.push({ input: entry.input, matched, match_method: method, tool: entry.tool });\n }\n return { results, warnings, methods, githubUrls };\n } catch (err) {\n warnings.push({\n scope: 'batch-resolve',\n message: `batch-resolve network failure: ${err instanceof Error ? err.message : String(err)}. Tools classified as non_oss.`,\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n }\n\n // ── Feedback ─────────────────────────────────────────────────────────────\n\n async reportOutcome(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/feedback/outcome', args);\n }\n\n async suggestGraphUpdate(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/feedback/suggest', args);\n }\n\n // ── Registration ─────────────────────────────────────────────────────────\n\n async register(clientId: string): Promise<{ ok: boolean; client_id: string }> {\n const res = await this.rawPost('/v1/register', { client_id: clientId });\n return res.json() as Promise<{ ok: boolean; client_id: string }>;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const res = await fetch(`${this.baseUrl}/v1/health`, {\n signal: AbortSignal.timeout(5_000),\n });\n return res.ok;\n } catch {\n return false;\n }\n }\n\n // ── Private ──────────────────────────────────────────────────────────────\n\n private async post(path: string, body: unknown): Promise<CallToolResult> {\n try {\n const res = await this.rawPost(path, body);\n const data = (await res.json()) as CallToolResult;\n\n // API returns a CallToolResult directly — pass it through\n if (data && typeof data === 'object' && 'content' in data) {\n return data;\n }\n\n // Unexpected response shape — wrap it\n return {\n content: [{ type: 'text', text: JSON.stringify(data) }],\n };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n ok: false,\n error: ErrorCode.ERR_NETWORK_UNREACHABLE,\n message: `ToolCairn API unreachable: ${msg}. Check your internet connection or try again later.`,\n }),\n },\n ],\n isError: true,\n };\n }\n }\n\n private rawPost(path: string, body: unknown): Promise<Response> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-ToolCairn-Key': this.apiKey,\n 'Accept-Encoding': 'gzip',\n };\n if (this.accessToken) {\n headers.Authorization = `Bearer ${this.accessToken}`;\n }\n return fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n }\n}\n","/**\n * Manages authentication credentials stored in ~/.toolcairn/credentials.json.\n * Authentication is required — there is no anonymous access.\n */\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CREDENTIALS_DIR = join(homedir(), '.toolcairn');\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\nconst PENDING_AUTH_FILE = join(CREDENTIALS_DIR, 'pending-auth.json');\n\nexport interface PendingAuth {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_at: string; // ISO timestamp\n api_url: string;\n}\n\nexport async function savePendingAuth(data: PendingAuth): Promise<void> {\n await mkdir(CREDENTIALS_DIR, { recursive: true });\n await writeFile(PENDING_AUTH_FILE, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport async function loadPendingAuth(): Promise<PendingAuth | null> {\n try {\n const raw = await readFile(PENDING_AUTH_FILE, 'utf-8');\n const data = JSON.parse(raw) as PendingAuth;\n if (new Date(data.expires_at) < new Date()) {\n await clearPendingAuth();\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\nexport async function clearPendingAuth(): Promise<void> {\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(PENDING_AUTH_FILE);\n } catch {\n // file didn't exist — that's fine\n }\n}\n\nexport interface Credentials {\n client_id: string;\n created_at: string;\n api_url?: string;\n access_token?: string;\n user_id?: string;\n user_email?: string;\n user_name?: string;\n authenticated_at?: string;\n}\n\n/**\n * Returns true if the credentials contain a valid, non-expired JWT access token.\n */\nexport function isTokenValid(creds: Credentials): boolean {\n if (!creds.access_token) return false;\n try {\n const parts = creds.access_token.split('.');\n if (parts.length !== 3) return false;\n // Decode payload without verifying signature — just check expiry client-side\n const payload = JSON.parse(Buffer.from(parts[1] ?? '', 'base64url').toString('utf-8')) as {\n exp?: number;\n };\n // Treat token as expired 5 min early to avoid race conditions\n if (payload.exp && payload.exp < Date.now() / 1000 + 300) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Load credentials from disk. Returns null if the file doesn't exist or has no valid token.\n */\nexport async function loadCredentials(): Promise<Credentials | null> {\n try {\n const raw = await readFile(CREDENTIALS_FILE, 'utf-8');\n return JSON.parse(raw) as Credentials;\n } catch {\n return null;\n }\n}\n\n/**\n * Load or create a minimal credentials stub (client_id only, no token).\n * Used as a placeholder before authentication completes.\n */\nexport async function loadOrCreateCredentials(): Promise<Credentials> {\n const existing = await loadCredentials();\n if (existing) return existing;\n\n const creds: Credentials = {\n client_id: crypto.randomUUID(),\n created_at: new Date().toISOString(),\n };\n await saveCredentials(creds);\n return creds;\n}\n\nexport async function saveCredentials(creds: Credentials): Promise<void> {\n await mkdir(CREDENTIALS_DIR, { recursive: true });\n await writeFile(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), 'utf-8');\n}\n\nexport async function getApiKey(): Promise<string> {\n const creds = await loadOrCreateCredentials();\n return creds.client_id;\n}\n\n/**\n * Merge authentication data into the existing credentials file.\n * Called after a successful device auth flow.\n */\nexport async function upgradeToAuthenticated(\n accessToken: string,\n apiKey: string,\n user: { id: string; email?: string | null; name?: string | null },\n): Promise<void> {\n const existing = await loadOrCreateCredentials();\n await saveCredentials({\n ...existing,\n client_id: apiKey,\n access_token: accessToken,\n user_id: user.id,\n user_email: user.email ?? undefined,\n user_name: user.name ?? undefined,\n authenticated_at: new Date().toISOString(),\n });\n}\n\n/**\n * Remove authentication data. Next startup will automatically trigger re-auth.\n */\nexport async function clearAuthentication(): Promise<void> {\n const existing = await loadOrCreateCredentials();\n await saveCredentials({\n client_id: existing.client_id,\n created_at: existing.created_at,\n api_url: existing.api_url,\n });\n}\n","/**\n * Device authorization flow for the MCP CLI.\n * Implements the OAuth 2.0 Device Authorization Grant (RFC 8628).\n *\n * Survives MCP process restarts: the device_code is written to\n * ~/.toolcairn/pending-auth.json immediately on first request.\n * On every subsequent startup, if this file exists and hasn't expired,\n * polling resumes automatically — no need to re-open the browser.\n */\nimport { AuthError, ErrorCode, NetworkError } from '@toolcairn/errors';\nimport {\n clearPendingAuth,\n loadPendingAuth,\n savePendingAuth,\n upgradeToAuthenticated,\n} from './credentials.js';\n\ninterface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n api_key: string;\n user: { id: string; email: string | null; name: string | null };\n error?: string;\n}\n\n/**\n * Open a URL in the default browser.\n * Uses spawn + detached so it works from stdio child processes (e.g. MCP server).\n * execSync blocks and fails silently in non-interactive contexts; spawn does not.\n */\nasync function openBrowser(url: string): Promise<void> {\n const { spawn } = await import('node:child_process');\n try {\n const platform = process.platform;\n let cmd: string;\n let args: string[];\n if (platform === 'win32') {\n cmd = 'cmd';\n args = ['/c', 'start', '', url];\n } else if (platform === 'darwin') {\n cmd = 'open';\n args = [url];\n } else {\n cmd = 'xdg-open';\n args = [url];\n }\n const child = spawn(cmd, args, { detached: true, stdio: 'ignore', shell: false });\n child.unref();\n } catch {\n // URL is printed to stderr as fallback\n }\n}\n\n/**\n * Request a new device code, persist it to ~/.toolcairn/pending-auth.json,\n * and open the browser automatically.\n *\n * Only call this on a FRESH start (no pending-auth.json). This is the only\n * place that opens the browser — the resume path in startDeviceAuth() never\n * opens the browser (prevents duplicate tabs on process restart).\n */\nexport async function requestDeviceCode(apiUrl: string): Promise<DeviceCodeResponse> {\n const res = await fetch(`${apiUrl}/v1/auth/device-code`, { method: 'POST' });\n if (!res.ok) {\n throw new NetworkError({\n code: ErrorCode.ERR_NETWORK_UNREACHABLE,\n message: 'Failed to start device auth. Check your internet connection.',\n });\n }\n const data = (await res.json()) as DeviceCodeResponse;\n\n // Persist immediately so polling can resume if this process is killed\n await savePendingAuth({\n device_code: data.device_code,\n user_code: data.user_code,\n verification_uri: data.verification_uri,\n expires_at: new Date(Date.now() + data.expires_in * 1000).toISOString(),\n api_url: apiUrl,\n });\n\n // Open browser here (fresh start only — resume path skips this)\n process.stderr.write('\\n──────────────────────────────────────────\\n');\n process.stderr.write(' ToolCairn — Sign In Required\\n');\n process.stderr.write('──────────────────────────────────────────\\n');\n process.stderr.write('\\n Opening browser for authentication...\\n\\n');\n process.stderr.write(` URL: ${data.verification_uri}\\n`);\n process.stderr.write(` Code: ${data.user_code}\\n\\n`);\n await openBrowser(data.verification_uri);\n\n return data;\n}\n\n/**\n * Start the full device auth flow — request code (or resume pending), open browser, poll.\n * Returns user info on success, throws on failure.\n *\n * On restart: if ~/.toolcairn/pending-auth.json exists and hasn't expired,\n * polling resumes for the same code (browser already opened, user might already\n * have confirmed — poll will return the token immediately).\n */\nexport async function startDeviceAuth(\n apiUrl: string,\n): Promise<{ userId: string; email: string; name: string | null }> {\n // Check for a pending auth from a previous (killed) process\n const pending = await loadPendingAuth();\n let codeData: DeviceCodeResponse;\n\n if (pending && pending.api_url === apiUrl) {\n // Resume from a previous (killed/restarted) process.\n // The browser was already opened — do NOT open it again (causes duplicate tabs).\n codeData = {\n device_code: pending.device_code,\n user_code: pending.user_code,\n verification_uri: pending.verification_uri,\n expires_in: Math.floor((new Date(pending.expires_at).getTime() - Date.now()) / 1000),\n interval: 5,\n };\n process.stderr.write('\\n ToolCairn: Waiting for sign-in confirmation...\\n');\n process.stderr.write(` URL: ${codeData.verification_uri}\\n`);\n process.stderr.write(` Code: ${codeData.user_code}\\n\\n`);\n // No openBrowser() call here — browser already open from previous session\n } else {\n // Fresh start — requestDeviceCode() opens the browser (only place that does)\n codeData = await requestDeviceCode(apiUrl);\n }\n\n const result = await pollForToken(apiUrl, codeData.device_code, 5);\n\n // Clear pending auth — successfully authenticated\n await clearPendingAuth();\n await upgradeToAuthenticated(result.access_token, result.api_key, result.user);\n\n process.stderr.write(`\\n ✓ Signed in as ${result.user.email}\\n\\n`);\n\n return {\n userId: result.user.id,\n email: result.user.email ?? '',\n name: result.user.name,\n };\n}\n\nasync function pollForToken(\n apiUrl: string,\n deviceCode: string,\n intervalSec: number,\n): Promise<TokenResponse> {\n const intervalMs = Math.max(intervalSec, 5) * 1000;\n\n while (true) {\n await sleep(intervalMs);\n\n const res = await fetch(`${apiUrl}/v1/auth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ device_code: deviceCode, grant_type: 'device_code' }),\n });\n\n const data = (await res.json()) as TokenResponse;\n\n if (data.error === 'authorization_pending') continue;\n if (data.error === 'expired_token') {\n await clearPendingAuth();\n throw new AuthError({\n code: ErrorCode.ERR_AUTH_TOKEN_EXPIRED,\n message: 'Device code expired. Please try again.',\n });\n }\n if (data.error) {\n throw new AuthError({\n code: ErrorCode.ERR_AUTH_UNAUTHORIZED,\n message: `Authorization failed: ${data.error}`,\n });\n }\n if (data.access_token) return data;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Project-level setup hooks — runs once at MCP server startup.\n *\n * As of v0.10.0 the MCP server NO LONGER auto-scaffolds `.toolcairn/config.json`\n * or `.toolcairn/events.jsonl`. Those files are owned by handler flows:\n * - `config.json` is created atomically by `mutateConfig` on the first call\n * that passes a `project_root` (cross-process locked, no race).\n * - `events.jsonl` is created on demand by the event-logger middleware when\n * `TOOLCAIRN_EVENTS_PATH` is set.\n *\n * What this module still does:\n * - Detects the host OS (for logging only).\n * - Writes `.toolcairn/tracker.html` — a read-only dashboard; safe to create at\n * startup because nothing else writes to it.\n *\n * The tracker's cwd placement is best-effort: `ensureProjectSetup` receives\n * `projectRoot` from the caller (the stdio server boot). If the agent later\n * invokes `toolcairn_init` with a different `project_root`, that handler bootstraps\n * config.json at the correct location via its own cross-process lock.\n */\n\nimport { access, mkdir, writeFile } from 'node:fs/promises';\nimport { platform, type } from 'node:os';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { generateTrackerHtml } from './tools/generate-tracker.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server:project-setup' });\n\n/**\n * Detect and return a human-readable OS label for logging.\n * Uses process.platform (win32 / darwin / linux / …).\n */\nfunction detectOs(): { platform: string; label: string } {\n const p = platform();\n const labels: Record<string, string> = {\n win32: 'Windows',\n darwin: 'macOS',\n linux: 'Linux',\n freebsd: 'FreeBSD',\n openbsd: 'OpenBSD',\n sunos: 'Solaris',\n android: 'Android',\n };\n return { platform: p, label: labels[p] ?? type() };\n}\n\n/**\n * Normalise an absolute file path to use forward slashes.\n * Required when embedding the path in a file:// URL inside tracker.html.\n * On Unix this is a no-op; on Windows it converts C:\\foo\\bar → C:/foo/bar.\n */\nfunction toFileUrl(absPath: string): string {\n return absPath.replace(/\\\\/g, '/');\n}\n\n/**\n * Ensure `.toolcairn/tracker.html` exists in `projectRoot`. No-op if already present.\n * Does NOT write `config.json` or `events.jsonl` — handlers own those.\n */\nexport async function ensureProjectSetup(projectRoot = process.cwd()): Promise<void> {\n const os = detectOs();\n logger.info(\n { os: os.label, platform: os.platform, projectRoot },\n 'Detected OS — starting project setup',\n );\n\n const dir = join(projectRoot, '.toolcairn');\n const trackerPath = join(dir, 'tracker.html');\n const eventsPathAbs = join(dir, 'events.jsonl');\n\n // tracker.html embeds the events path in a file:// URL — must use forward slashes\n const eventsPathForUrl = toFileUrl(eventsPathAbs);\n\n try {\n await mkdir(dir, { recursive: true });\n await createIfAbsent(trackerPath, generateTrackerHtml(eventsPathForUrl), 'tracker.html');\n logger.info({ dir, os: os.label }, '.toolcairn tracker ready');\n } catch (e) {\n // Non-fatal — server still starts even if setup fails (read-only fs, perms, etc.)\n logger.warn(\n { err: e, dir, os: os.label },\n 'tracker.html setup failed — continuing (config.json still bootstrapped by handlers)',\n );\n }\n}\n\nasync function createIfAbsent(filePath: string, content: string, label: string): Promise<void> {\n try {\n await access(filePath);\n logger.debug({ file: label }, 'Already exists — skipping');\n } catch {\n await writeFile(filePath, content, 'utf-8');\n logger.info({ file: label }, 'Created');\n }\n}\n","/**\n * Generate the standalone tracker.html content.\n * Called by toolcairn_init to produce the HTML file content.\n * The agent writes the returned content to .toolcairn/tracker.html\n */\nexport function generateTrackerHtml(eventsPath: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n<title>ToolCairn Tracker</title>\n<style>\n :root {\n --bg: #0a0a0f;\n --surface: #12121a;\n --surface2: #1a1a26;\n --border: #2a2a3a;\n --accent: #7c5cfc;\n --accent2: #5b8def;\n --green: #22c55e;\n --red: #ef4444;\n --yellow: #f59e0b;\n --text: #e2e8f0;\n --muted: #64748b;\n --mono: 'JetBrains Mono', 'Fira Code', monospace;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { background: var(--bg); color: var(--text); font-family: system-ui, sans-serif; font-size: 14px; min-height: 100vh; }\n\n header { display: flex; align-items: center; gap: 12px; padding: 16px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }\n header h1 { font-size: 16px; font-weight: 700; letter-spacing: -0.02em; }\n header h1 span { color: var(--accent); }\n .status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); animation: pulse 2s infinite; margin-left: auto; }\n .status-dot.paused { background: var(--yellow); animation: none; }\n @keyframes pulse { 0%,100%{ opacity:1; } 50%{ opacity:0.4; } }\n\n .controls { display: flex; gap: 8px; align-items: center; padding: 12px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }\n .btn { padding: 5px 12px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface2); color: var(--text); cursor: pointer; font-size: 12px; transition: border-color .15s; }\n .btn:hover { border-color: var(--accent); }\n .btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }\n input[type=range] { accent-color: var(--accent); }\n .label { color: var(--muted); font-size: 12px; }\n\n .metrics { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 1px; background: var(--border); border-bottom: 1px solid var(--border); }\n .metric { background: var(--surface); padding: 14px 18px; }\n .metric-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px; }\n .metric-value { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }\n .metric-value.green { color: var(--green); }\n .metric-value.red { color: var(--red); }\n .metric-value.accent { color: var(--accent); }\n .metric-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }\n\n .layout { display: grid; grid-template-columns: 1fr 340px; height: calc(100vh - 140px); }\n .feed { overflow-y: auto; border-right: 1px solid var(--border); }\n .sidebar { overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; }\n\n .event-row { display: grid; grid-template-columns: 80px 160px 1fr auto auto; gap: 12px; align-items: center; padding: 8px 16px; border-bottom: 1px solid #1a1a22; transition: background .1s; cursor: pointer; }\n .event-row:hover { background: var(--surface2); }\n .event-row.selected { background: #1e1a30; }\n .event-row .time { font-family: var(--mono); font-size: 11px; color: var(--muted); }\n .event-row .tool { font-family: var(--mono); font-size: 12px; color: var(--accent); font-weight: 600; }\n .event-row .summary { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .event-row .dur { font-family: var(--mono); font-size: 11px; color: var(--muted); text-align: right; }\n .badge { display: inline-flex; align-items: center; padding: 2px 7px; border-radius: 4px; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }\n .badge.ok { background: rgba(34,197,94,.15); color: var(--green); }\n .badge.error { background: rgba(239,68,68,.15); color: var(--red); }\n .badge.warn { background: rgba(245,158,11,.15); color: var(--yellow); }\n\n .detail-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 14px; }\n .detail-card h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 10px; }\n .kv { display: flex; justify-content: space-between; padding: 3px 0; border-bottom: 1px solid #1a1a22; font-size: 12px; }\n .kv:last-child { border-bottom: none; }\n .kv .k { color: var(--muted); }\n .kv .v { font-family: var(--mono); color: var(--text); }\n .kv .v.green { color: var(--green); }\n .kv .v.red { color: var(--red); }\n .kv .v.yellow { color: var(--yellow); }\n\n .bar-chart { margin-top: 6px; }\n .bar-row { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; font-size: 11px; }\n .bar-label { width: 120px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: right; }\n .bar-track { flex: 1; height: 6px; background: var(--surface2); border-radius: 3px; }\n .bar-fill { height: 100%; border-radius: 3px; background: var(--accent); transition: width .3s; }\n .bar-count { width: 28px; text-align: right; color: var(--text); }\n\n .empty { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--muted); gap: 8px; }\n .empty svg { opacity: .3; }\n .empty p { font-size: 13px; }\n .empty code { font-family: var(--mono); font-size: 11px; background: var(--surface2); padding: 3px 8px; border-radius: 4px; color: var(--accent); }\n\n .insights-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }\n .insight-item { background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; font-size: 12px; }\n .insight-item .i-tool { color: var(--accent); font-family: var(--mono); font-weight: 600; }\n .insight-item .i-text { color: var(--muted); margin-top: 2px; }\n\n ::-webkit-scrollbar { width: 4px; }\n ::-webkit-scrollbar-track { background: transparent; }\n ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }\n</style>\n</head>\n<body>\n\n<header>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <circle cx=\"10\" cy=\"10\" r=\"9\" stroke=\"#7c5cfc\" stroke-width=\"1.5\"/>\n <path d=\"M6 10h8M10 6v8\" stroke=\"#7c5cfc\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <h1><span>Tool</span>Pilot Tracker</h1>\n <div id=\"statusText\" style=\"font-size:12px; color:var(--muted);\">Loading...</div>\n <div id=\"statusDot\" class=\"status-dot paused\"></div>\n</header>\n\n<div class=\"controls\">\n <button class=\"btn active\" id=\"btnLive\" onclick=\"toggleLive()\">⬤ Live</button>\n <button class=\"btn\" id=\"btnClear\" onclick=\"clearEvents()\">Clear</button>\n <span class=\"label\" style=\"margin-left:8px;\">Interval:</span>\n <input type=\"range\" min=\"1\" max=\"30\" value=\"3\" id=\"intervalSlider\" onchange=\"setInterval_(this.value)\" style=\"width:80px;\" />\n <span class=\"label\" id=\"intervalLabel\">3s</span>\n <span style=\"margin-left:auto; font-size:11px; color:var(--muted);\" id=\"lastRefresh\">—</span>\n</div>\n\n<div class=\"metrics\" id=\"metrics\">\n <div class=\"metric\"><div class=\"metric-label\">Total Calls</div><div class=\"metric-value accent\" id=\"mTotal\">0</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Success Rate</div><div class=\"metric-value green\" id=\"mSuccess\">—</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Avg Latency</div><div class=\"metric-value\" id=\"mLatency\">—</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Issues Caught</div><div class=\"metric-value yellow\" id=\"mIssues\">0</div><div class=\"metric-sub\">check_issue calls</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Deprecation Warns</div><div class=\"metric-value yellow\" id=\"mDeprecation\">0</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Non-OSS Guided</div><div class=\"metric-value\" id=\"mNonOss\">0</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Graph Updates</div><div class=\"metric-value accent\" id=\"mGraph\">0</div></div>\n</div>\n\n<div class=\"layout\">\n <div class=\"feed\" id=\"feed\">\n <div class=\"empty\" id=\"emptyState\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\"><circle cx=\"20\" cy=\"20\" r=\"18\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\"/><path d=\"M13 20h14M20 13v14\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>\n <p>Waiting for MCP tool calls...</p>\n <code>Set TOOLCAIRN_EVENTS_PATH in your MCP server env</code>\n </div>\n </div>\n <div class=\"sidebar\">\n <div class=\"detail-card\" id=\"detailPanel\" style=\"display:none\">\n <h3>Event Detail</h3>\n <div id=\"detailContent\"></div>\n </div>\n <div class=\"detail-card\">\n <h3>Calls by Tool</h3>\n <div id=\"toolChart\" class=\"bar-chart\"></div>\n </div>\n <div class=\"detail-card\">\n <h3>Recent Insights</h3>\n <ul class=\"insights-list\" id=\"insightsList\"></ul>\n </div>\n </div>\n</div>\n\n<script>\n// ─── Config ──────────────────────────────────────────────────────────────────\nconst EVENTS_PATH = ${JSON.stringify(eventsPath)};\n\n// ─── State ───────────────────────────────────────────────────────────────────\nlet allEvents = [];\nlet selectedId = null;\nlet isLive = true;\nlet pollIntervalMs = 3000;\nlet pollHandle = null;\nlet lastByteOffset = 0;\n\n// ─── Polling ──────────────────────────────────────────────────────────────────\nasync function fetchEvents() {\n if (!EVENTS_PATH) return;\n try {\n // Fetch with range header to only get new bytes\n const headers = lastByteOffset > 0 ? { 'Range': \\`bytes=\\${lastByteOffset}-\\` } : {};\n const res = await fetch(\\`file://\\${EVENTS_PATH}\\`, { headers }).catch(() => null);\n if (!res) return;\n\n const text = await res.text();\n if (!text.trim()) return;\n\n const newLines = text.trim().split('\\\\n').filter(Boolean);\n let added = 0;\n for (const line of newLines) {\n try {\n const ev = JSON.parse(line);\n if (!allEvents.find(e => e.id === ev.id)) {\n allEvents.push(ev);\n added++;\n }\n } catch {}\n }\n\n if (added > 0) {\n allEvents.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));\n renderAll();\n }\n\n document.getElementById('lastRefresh').textContent = 'Updated ' + new Date().toLocaleTimeString();\n document.getElementById('statusDot').className = 'status-dot' + (isLive ? '' : ' paused');\n document.getElementById('statusText').textContent = \\`\\${allEvents.length} events\\`;\n } catch (e) {\n console.warn('Fetch error', e);\n }\n}\n\nfunction toggleLive() {\n isLive = !isLive;\n document.getElementById('btnLive').className = 'btn' + (isLive ? ' active' : '');\n document.getElementById('statusDot').className = 'status-dot' + (isLive ? '' : ' paused');\n if (isLive) startPolling(); else stopPolling();\n}\n\nfunction clearEvents() {\n allEvents = [];\n selectedId = null;\n renderAll();\n}\n\nfunction setInterval_(v) {\n pollIntervalMs = Number(v) * 1000;\n document.getElementById('intervalLabel').textContent = v + 's';\n if (isLive) { stopPolling(); startPolling(); }\n}\n\nfunction startPolling() {\n if (pollHandle) clearInterval(pollHandle);\n fetchEvents();\n pollHandle = setInterval(fetchEvents, pollIntervalMs);\n}\n\nfunction stopPolling() {\n if (pollHandle) { clearInterval(pollHandle); pollHandle = null; }\n}\n\n// ─── Render ───────────────────────────────────────────────────────────────────\nfunction fmtTime(iso) {\n return new Date(iso).toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nfunction toolSummary(ev) {\n const m = ev.metadata || {};\n if (ev.tool_name === 'search_tools' || ev.tool_name === 'search_tools_respond') {\n const parts = [];\n if (m.is_two_option) parts.push('2-option result');\n if (m.had_non_indexed_guidance) parts.push('non-OSS guidance');\n if (m.had_deprecation_warning) parts.push('⚠ deprecated tool');\n if (m.had_credibility_warning) parts.push('⚠ low-stars warning');\n return parts.join(' · ') || m.status || '';\n }\n if (ev.tool_name === 'check_issue') return m.status ? \\`status: \\${m.status}\\` : '';\n if (ev.tool_name === 'suggest_graph_update') {\n if (m.auto_graduated) return '✓ auto-graduated to graph';\n if (m.staged) return 'staged for review';\n return '';\n }\n if (ev.tool_name === 'compare_tools') return m.recommendation ? \\`rec: \\${m.recommendation}\\` : '';\n if (ev.tool_name === 'check_compatibility') return m.compatibility_signal ? m.compatibility_signal : '';\n return m.status || '';\n}\n\nfunction renderFeed() {\n const feed = document.getElementById('feed');\n const empty = document.getElementById('emptyState');\n if (allEvents.length === 0) {\n empty.style.display = 'flex';\n feed.querySelectorAll('.event-row').forEach(r => r.remove());\n return;\n }\n empty.style.display = 'none';\n\n // Remove rows not in allEvents\n const existingIds = new Set(Array.from(feed.querySelectorAll('.event-row')).map(r => r.dataset.id));\n const currentIds = new Set(allEvents.map(e => e.id));\n existingIds.forEach(id => { if (!currentIds.has(id)) feed.querySelector(\\`[data-id=\"\\${id}\"]\\`)?.remove(); });\n\n // Add new rows at top\n for (const ev of allEvents) {\n if (feed.querySelector(\\`[data-id=\"\\${ev.id}\"]\\`)) continue;\n const row = document.createElement('div');\n row.className = 'event-row' + (selectedId === ev.id ? ' selected' : '');\n row.dataset.id = ev.id;\n row.onclick = () => selectEvent(ev.id);\n\n const badgeClass = ev.status === 'ok' ? 'ok' : 'error';\n const summary = toolSummary(ev);\n row.innerHTML = \\`\n <span class=\"time\">\\${fmtTime(ev.created_at)}</span>\n <span class=\"tool\">\\${ev.tool_name}</span>\n <span class=\"summary\">\\${summary}</span>\n <span class=\"dur\">\\${ev.duration_ms}ms</span>\n <span class=\"badge \\${badgeClass}\">\\${ev.status}</span>\n \\`;\n\n // Insert in chronological order (newest first)\n const firstRow = feed.querySelector('.event-row');\n if (firstRow) feed.insertBefore(row, firstRow);\n else feed.appendChild(row);\n }\n}\n\nfunction renderMetrics() {\n const total = allEvents.length;\n const okCount = allEvents.filter(e => e.status === 'ok').length;\n const avgMs = total > 0 ? Math.round(allEvents.reduce((s, e) => s + e.duration_ms, 0) / total) : 0;\n const issueCount = allEvents.filter(e => e.tool_name === 'check_issue').length;\n const deprecCount = allEvents.filter(e => e.metadata?.had_deprecation_warning).length;\n const nonOssCount = allEvents.filter(e => e.metadata?.had_non_indexed_guidance).length;\n const graphCount = allEvents.filter(e => e.tool_name === 'suggest_graph_update').length;\n\n document.getElementById('mTotal').textContent = total;\n document.getElementById('mSuccess').textContent = total > 0 ? Math.round(okCount / total * 100) + '%' : '—';\n document.getElementById('mLatency').textContent = total > 0 ? avgMs + 'ms' : '—';\n document.getElementById('mIssues').textContent = issueCount;\n document.getElementById('mDeprecation').textContent = deprecCount;\n document.getElementById('mNonOss').textContent = nonOssCount;\n document.getElementById('mGraph').textContent = graphCount;\n}\n\nfunction renderToolChart() {\n const counts = {};\n for (const ev of allEvents) counts[ev.tool_name] = (counts[ev.tool_name] || 0) + 1;\n const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, 8);\n const max = sorted[0]?.[1] || 1;\n const html = sorted.map(([tool, count]) => \\`\n <div class=\"bar-row\">\n <span class=\"bar-label\">\\${tool}</span>\n <div class=\"bar-track\"><div class=\"bar-fill\" style=\"width:\\${count/max*100}%\"></div></div>\n <span class=\"bar-count\">\\${count}</span>\n </div>\n \\`).join('');\n document.getElementById('toolChart').innerHTML = html || '<span style=\"color:var(--muted);font-size:12px\">No data yet</span>';\n}\n\nfunction renderInsights() {\n const insights = [];\n for (const ev of allEvents.slice(0, 50)) {\n const m = ev.metadata || {};\n if (ev.tool_name === 'check_issue' && ev.status === 'ok') {\n insights.push({ tool: ev.tool_name, text: 'Issue check ran — may have prevented a debug loop', time: ev.created_at });\n }\n if (m.had_deprecation_warning) {\n insights.push({ tool: ev.tool_name, text: 'Deprecated/unmaintained tool detected in results', time: ev.created_at });\n }\n if (m.auto_graduated) {\n insights.push({ tool: 'suggest_graph_update', text: 'New edge auto-graduated to graph (confidence ≥0.8)', time: ev.created_at });\n }\n if (m.had_non_indexed_guidance) {\n insights.push({ tool: ev.tool_name, text: 'Non-indexed tool detected — non-OSS guidance provided', time: ev.created_at });\n }\n if (m.recommendation) {\n insights.push({ tool: 'compare_tools', text: \\`Tool comparison recommended: \\${m.recommendation}\\`, time: ev.created_at });\n }\n }\n const list = document.getElementById('insightsList');\n if (insights.length === 0) {\n list.innerHTML = '<li style=\"color:var(--muted);font-size:12px\">No insights yet</li>';\n return;\n }\n list.innerHTML = insights.slice(0, 8).map(i => \\`\n <li class=\"insight-item\">\n <div class=\"i-tool\">\\${i.tool}</div>\n <div class=\"i-text\">\\${i.text}</div>\n </li>\n \\`).join('');\n}\n\nfunction selectEvent(id) {\n selectedId = id;\n document.querySelectorAll('.event-row').forEach(r => r.classList.toggle('selected', r.dataset.id === id));\n const ev = allEvents.find(e => e.id === id);\n if (!ev) return;\n const panel = document.getElementById('detailPanel');\n const content = document.getElementById('detailContent');\n panel.style.display = 'block';\n const m = ev.metadata || {};\n const rows = [\n ['Tool', ev.tool_name],\n ['Status', ev.status],\n ['Duration', ev.duration_ms + 'ms'],\n ['Time', new Date(ev.created_at).toLocaleString()],\n ev.query_id ? ['Session ID', ev.query_id.slice(0, 8) + '...'] : null,\n ...Object.entries(m).filter(([k]) => k !== 'tool').map(([k, v]) => [k, String(v)])\n ].filter(Boolean);\n content.innerHTML = rows.map(([k, v]) => {\n const cls = v === 'true' || v === 'ok' ? 'green' : v === 'false' || v === 'error' ? 'red' : '';\n return \\`<div class=\"kv\"><span class=\"k\">\\${k}</span><span class=\"v \\${cls}\">\\${v}</span></div>\\`;\n }).join('');\n}\n\nfunction renderAll() {\n renderFeed();\n renderMetrics();\n renderToolChart();\n renderInsights();\n}\n\n// ─── Boot ─────────────────────────────────────────────────────────────────────\nif (!EVENTS_PATH || EVENTS_PATH === 'null') {\n document.getElementById('statusText').textContent = 'No events path configured';\n document.getElementById('emptyState').querySelector('p').textContent = 'TOOLCAIRN_EVENTS_PATH not set in MCP server environment';\n} else {\n startPolling();\n}\n</script>\n</body>\n</html>`;\n}\n","/**\n * Production MCP server — thin HTTP bridge.\n *\n * LOCAL tools (classify_prompt, *_config, toolcairn_init) run directly.\n * All other tools make a single HTTP call to the ToolCairn API via ToolCairnClient.\n *\n * This file is used when TOOLPILOT_MODE=production (npx @toolcairn/mcp).\n * It intentionally imports NOTHING from @toolcairn/graph, @toolcairn/search,\n * @toolcairn/vector, @toolcairn/db, or @toolcairn/queue so those packages\n * are not bundled into the published npm package.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { config } from '@toolcairn/config';\nimport { createMcpLogger, withErrorHandling } from '@toolcairn/errors';\nimport {\n ToolCairnClient,\n clearAuthentication,\n isTokenValid,\n loadCredentials,\n startDeviceAuth,\n} from '@toolcairn/remote';\n// Use the /local subpath — excludes heavy DB/search/graph deps from the npm bundle.\n// The full '@toolcairn/tools' CJS dist requires Prisma/neo4j/ioredis at load time\n// even though prod mode never calls those code paths.\nimport {\n checkCompatibilitySchema,\n checkIssueSchema,\n classifyPromptSchema,\n compareToolsSchema,\n getStackSchema,\n handleClassifyPrompt,\n handleReadProjectConfig,\n handleToolcairnInit,\n handleUpdateProjectConfig,\n readProjectConfigSchema,\n refineRequirementSchema,\n reportOutcomeSchema,\n searchToolsRespondSchema,\n searchToolsSchema,\n suggestGraphUpdateSchema,\n toolcairnInitSchema,\n updateProjectConfigSchema,\n verifySuggestionSchema,\n} from '@toolcairn/tools-local';\nimport { z } from 'zod';\nimport { withEventLogging } from './middleware/event-logger.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server:prod' });\n\nconst SETUP_INSTRUCTIONS = `\n# ToolCairn — Agent Setup Instructions\n\nYou are connected to the ToolCairn MCP server. ToolCairn is your active tool intelligence co-pilot.\n\n## The Server Owns .toolcairn/ (v0.10.0+)\n\nThe MCP server reads and writes \\`.toolcairn/config.json\\` + \\`.toolcairn/audit-log.jsonl\\`\natomically under a cross-process lock. You never touch those files directly.\n\n## On Every Session Start — Do This First\n\nCall \\`read_project_config\\` with \\`project_root\\` (absolute path to the user's project).\n- If it returns \\`status: \"not_initialized\"\\`: the project has no config yet. Call\n \\`toolcairn_init\\` with \\`agent\\` (your type) + \\`project_root\\`. The server walks\n every workspace, parses manifests across 12 ecosystems, classifies tools against\n the ToolCairn graph, and atomically writes \\`.toolcairn/config.json\\`.\n After that, apply the returned \\`setup_steps\\` (append rules to CLAUDE.md,\n merge the toolcairn entry into .mcp.json, update .gitignore).\n- If it returns \\`status: \"ready\"\\`: you have the full project snapshot. Review\n \\`stale_tools\\` / \\`pending_tools\\` and proceed with work.\n\n## Applying Mutations\n\nWhen the user selects / replaces / drops a tool, call \\`update_project_config\\`\nwith \\`project_root\\`, \\`action\\` (add_tool / remove_tool / update_tool / add_evaluation),\nand \\`tool_name\\`. The server:\n- atomically updates \\`.toolcairn/config.json\\`,\n- appends a new line to \\`.toolcairn/audit-log.jsonl\\` (FIFO-archived at 1000 entries),\n- returns the new \\`last_audit_entry\\` for your record.\n\nDo NOT construct or write these files yourself — you do not have the cross-process\nlock that protects them.\n\n## Schema Migration\n\nConfigs written by v0.9.x are on schema 1.0. The first \\`read_project_config\\` or\n\\`update_project_config\\` call after upgrade migrates in place to 1.1 (languages →\narray, frameworks → array, \\`audit_log[]\\` relocated from config.json to\naudit-log.jsonl). The migration is logged as an audit entry.\n\n## When to Use ToolCairn Tools\n\n| Situation | Tool to call |\n|-----------|-------------|\n| User asks which tool to use for X | \\`classify_prompt\\` → \\`refine_requirement\\` → \\`search_tools\\` |\n| User needs to compare two tools | \\`compare_tools\\` |\n| User asks if tool A works with tool B | \\`check_compatibility\\` |\n| Error persists after 4+ retries AND docs checked | \\`check_issue\\` |\n| User asks for a recommended stack | \\`get_stack\\` |\n| search_tools returns empty or low confidence | \\`verify_suggestion\\` |\n| You discover a new tool relationship | \\`suggest_graph_update\\` |\n| A tool worked well or was replaced | \\`report_outcome\\` |\n| Tool added/removed from project | \\`update_project_config\\` |\n`.trim();\n\n/**\n * Register all 14 production tools (local + remote) on an existing McpServer.\n * Called either during buildProdServer() or dynamically after auth completes\n * on the waiting server — the MCP SDK notifies the client via\n * notifications/tools/list_changed so tools appear without reconnect.\n */\nexport async function addToolsToServer(server: McpServer): Promise<void> {\n const creds = await loadCredentials();\n if (!creds || !isTokenValid(creds)) {\n throw new Error('ToolCairn: authentication required.');\n }\n\n const remote = new ToolCairnClient({\n baseUrl: config.TOOLPILOT_API_URL,\n apiKey: creds.client_id,\n accessToken: creds.access_token,\n });\n\n logger.info({ user: creds.user_email }, 'Registering production tools');\n\n /**\n * Composes event logging + error handling around a tool handler.\n * Execution order: withEventLogging → withErrorHandling → handler\n * This ensures events are always recorded even when errors occur.\n *\n * Uses Record<string, unknown> at the composition boundary — individual\n * handlers still receive the validated args from their own Zod schemas.\n */\n type AnyHandler = (\n args: Record<string, unknown>,\n ) => Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>;\n function wrap(toolName: string, fn: AnyHandler) {\n return withEventLogging(toolName, withErrorHandling(toolName, logger, fn));\n }\n\n // ── LOCAL tools (zero network, run on user's machine) ──────────────────────\n\n server.registerTool(\n 'classify_prompt',\n {\n description:\n 'Classify a developer prompt to determine if ToolCairn tool search is needed. Returns a structured classification prompt for the agent to evaluate.',\n inputSchema: classifyPromptSchema,\n },\n wrap('classify_prompt', async (args) =>\n handleClassifyPrompt(args as Parameters<typeof handleClassifyPrompt>[0]),\n ),\n );\n\n server.registerTool(\n 'toolcairn_init',\n {\n description:\n 'Bootstrap ToolCairn for the current project. Walks every workspace, parses manifests across 12 ecosystems, classifies tools against the ToolCairn graph, and writes .toolcairn/config.json + audit-log.jsonl atomically. Returns setup_steps for CLAUDE.md / .mcp.json / .gitignore (agent applies those).',\n inputSchema: toolcairnInitSchema,\n },\n wrap('toolcairn_init', async (args) =>\n handleToolcairnInit(args as Parameters<typeof handleToolcairnInit>[0], {\n batchResolve: (items) => remote.batchResolve(items),\n }),\n ),\n );\n\n server.registerTool(\n 'read_project_config',\n {\n description:\n 'Read .toolcairn/config.json from disk and return the structured project snapshot: project metadata, confirmed tools, stale tools, pending evaluations, and last audit entry. Auto-migrates v1.0 configs to v1.1 on first read.',\n inputSchema: readProjectConfigSchema,\n },\n wrap('read_project_config', async (args) =>\n handleReadProjectConfig(args as Parameters<typeof handleReadProjectConfig>[0]),\n ),\n );\n\n server.registerTool(\n 'update_project_config',\n {\n description:\n 'Apply a mutation to .toolcairn/config.json (add_tool / remove_tool / update_tool / add_evaluation). The server atomically rewrites config.json and appends a new line to audit-log.jsonl under a cross-process lock. Requires project_root.',\n inputSchema: updateProjectConfigSchema,\n },\n wrap('update_project_config', async (args) =>\n handleUpdateProjectConfig(args as Parameters<typeof handleUpdateProjectConfig>[0]),\n ),\n );\n\n // ── REMOTE tools (one HTTP call each to ToolCairn API) ────────────────────\n\n server.registerTool(\n 'search_tools',\n {\n description:\n 'Search for the best tool for a specific need using a natural language query. Initiates a guided discovery session with clarification questions when needed.',\n inputSchema: searchToolsSchema,\n },\n wrap('search_tools', async (args) => remote.searchTools(args)),\n );\n\n server.registerTool(\n 'search_tools_respond',\n {\n description:\n 'Submit clarification answers for an in-progress tool search session and receive refined results.',\n inputSchema: searchToolsRespondSchema,\n },\n wrap('search_tools_respond', async (args) => remote.searchToolsRespond(args)),\n );\n\n server.registerTool(\n 'get_stack',\n {\n description:\n 'Build a complementary tool stack for a project use case. For best results, call refine_requirement first with classification \"stack_building\", evaluate its decomposition_prompt to get sub-needs, then pass each {sub_need_type, keyword_sentence} object as a sub_needs entry. This lets get_stack keyword-match per layer (e.g. \"web-framework\", \"database\", \"auth\") instead of one broad search. Falls back to balanced search when sub_needs is omitted. Each tool in the returned stack also carries a `version` object with the recommended version that is cross-compatible with the rest of the stack (downgraded from latest if needed to satisfy peer constraints), plus a top-level `compatibility_matrix` + `stack_compatibility` summarising cross-tool version fit.',\n inputSchema: getStackSchema,\n },\n wrap('get_stack', async (args) => remote.getStack(args)),\n );\n\n server.registerTool(\n 'check_compatibility',\n {\n description:\n 'Check compatibility between two tools with version-aware matching. When both tools have declared dependency metadata (npm peerDependencies, PyPI requires_dist, etc.) the handler evaluates range constraints directly and returns a version_checks array plus runtime_requirements. Pass optional tool_a_version / tool_b_version to evaluate specific versions (e.g. \"is next@14 compatible with react@17?\"). Falls back to graph-edge + shared-neighbors inference when version metadata is unavailable. Response includes `source`: \"declared_dependency\" | \"graph_edges\" | \"shared_neighbors\".',\n inputSchema: checkCompatibilitySchema,\n },\n wrap('check_compatibility', async (args) => remote.checkCompatibility(args)),\n );\n\n server.registerTool(\n 'compare_tools',\n {\n description:\n 'Compare two tools head-to-head using health signals, graph relationships, and community data.',\n inputSchema: compareToolsSchema,\n },\n wrap('compare_tools', async (args) => remote.compareTools(args)),\n );\n\n server.registerTool(\n 'refine_requirement',\n {\n description: 'Decompose a vague user use-case into specific, searchable tool requirements.',\n inputSchema: refineRequirementSchema,\n },\n wrap('refine_requirement', async (args) => remote.refineRequirement(args)),\n );\n\n server.registerTool(\n 'check_issue',\n {\n description:\n 'LAST RESORT — check GitHub Issues for a known error after 4+ retries and docs review.',\n inputSchema: checkIssueSchema,\n },\n wrap('check_issue', async (args) => remote.checkIssue(args)),\n );\n\n server.registerTool(\n 'verify_suggestion',\n {\n description: 'Validate agent-suggested tools against the ToolCairn graph.',\n inputSchema: verifySuggestionSchema,\n },\n wrap('verify_suggestion', async (args) => remote.verifySuggestion(args)),\n );\n\n server.registerTool(\n 'report_outcome',\n {\n description: 'Report the outcome of using a tool recommended by ToolCairn (fire-and-forget).',\n inputSchema: reportOutcomeSchema,\n },\n wrap('report_outcome', async (args) => remote.reportOutcome(args)),\n );\n\n server.registerTool(\n 'suggest_graph_update',\n {\n description:\n 'Suggest a new tool, relationship, use case, or health update to the ToolCairn graph.',\n inputSchema: suggestGraphUpdateSchema,\n },\n wrap('suggest_graph_update', async (args) => remote.suggestGraphUpdate(args)),\n );\n\n // ── AUTH tool (local — manages ~/.toolcairn/credentials.json) ─────────────\n\n server.registerTool(\n 'toolcairn_auth',\n {\n description:\n 'Manage your ToolCairn authentication. Use \"login\" to authenticate via browser (unlocks higher rate limits), \"status\" to check current auth state, or \"logout\" to revert to anonymous mode.',\n inputSchema: z.object({\n action: z\n .enum(['login', 'status', 'logout'])\n .describe(\n '\"login\" opens a browser to authenticate, \"status\" shows current auth state, \"logout\" clears authentication',\n ),\n }),\n },\n async ({ action }) => {\n if (action === 'status') {\n const c = await loadCredentials();\n const isAuth = c !== null && isTokenValid(c);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n authenticated: isAuth,\n user_email: c?.user_email ?? null,\n user_name: c?.user_name ?? null,\n authenticated_at: c?.authenticated_at ?? null,\n }),\n },\n ],\n };\n }\n\n if (action === 'logout') {\n await clearAuthentication();\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n ok: true,\n message:\n 'Signed out. Restart your agent to sign in again — authentication will start automatically.',\n }),\n },\n ],\n };\n }\n\n // action === 'login'\n try {\n const user = await startDeviceAuth(config.TOOLPILOT_API_URL);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n ok: true,\n message: `Successfully authenticated as ${user.email}. All tools are now authorized.`,\n user_email: user.email,\n user_name: user.name,\n }),\n },\n ],\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Authentication failed';\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ ok: false, error: msg }) }],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Build a new fully-authenticated prod server.\n * Creates the McpServer then delegates tool registration to addToolsToServer().\n */\nexport async function buildProdServer(): Promise<McpServer> {\n const server = new McpServer(\n { name: 'toolcairn', version: '0.1.0' },\n { instructions: SETUP_INSTRUCTIONS },\n );\n await addToolsToServer(server);\n return server;\n}\n","/**\n * @toolcairn/tools-local\n *\n * Production-safe handlers and schemas — zero DB/search/graph dependencies.\n * Used by the published MCP server bundle (npx @neurynae/toolcairn-mcp).\n *\n * Local handlers run entirely on the user's machine.\n * Remote tool schemas are re-exported here for MCP tool registration.\n */\n\n// Zod input schemas (all tools — needed for MCP tool registration in prod server)\nexport * from './schemas.js';\n\n// Type utilities\nexport { okResult, errResult } from './utils.js';\nexport type { FormattedResult } from './format-results.js';\n\n// Local handlers — run entirely on the user's machine, zero DB deps\nexport { handleClassifyPrompt } from './handlers/classify-prompt.js';\nexport {\n handleToolcairnInit,\n type HandleToolcairnInitDeps,\n} from './handlers/toolcairn-init.js';\nexport { handleReadProjectConfig } from './handlers/read-project-config.js';\nexport { handleUpdateProjectConfig } from './handlers/update-project-config.js';\n\n// Discovery + config-store — exported for local E2E / direct embedding\nexport * from './discovery/index.js';\nexport {\n mutateConfig,\n readConfig,\n writeConfig,\n appendAudit,\n bulkAppendAudit,\n readLiveAudit,\n migrateToV1_1,\n emptySkeleton,\n joinConfigPath,\n joinAuditPath,\n joinConfigDir,\n CONFIG_DIR,\n CONFIG_FILE,\n AUDIT_LOG_FILE,\n AUDIT_ARCHIVE_FILE,\n type Mutator,\n type MutateResult,\n type PendingAuditEntry,\n type MigrateResult,\n type ReadConfigResult,\n} from './config-store/index.js';\n","import { z } from 'zod';\n\nexport const searchToolsSchema = {\n query: z.string().min(1).max(500),\n context: z.object({ filters: z.record(z.string(), z.unknown()) }).optional(),\n query_id: z.string().uuid().optional(),\n user_id: z.string().optional(),\n};\n\nexport const searchToolsRespondSchema = {\n query_id: z.string().uuid(),\n answers: z.array(z.object({ dimension: z.string(), value: z.string() })),\n};\n\nexport const reportOutcomeSchema = {\n query_id: z.string().uuid(),\n chosen_tool: z.string(),\n reason: z.string().optional(),\n outcome: z.enum(['success', 'failure', 'replaced', 'pending']),\n feedback: z.string().optional(),\n replaced_by: z.string().optional(),\n};\n\nexport const getStackSchema = {\n use_case: z.string().min(1),\n sub_needs: z\n .array(\n z.union([\n z.string().min(1),\n z.object({\n sub_need_type: z\n .string()\n .min(1)\n .max(50)\n .describe('Stack layer type, e.g. \"database\", \"auth\", \"web-framework\"'),\n keyword_sentence: z\n .string()\n .min(1)\n .max(500)\n .describe('Comma-separated keywords matching tool vocabulary, max 20 keywords'),\n }),\n ]),\n )\n .min(1)\n .max(8)\n .optional()\n .describe(\n 'Structured sub-needs from refine_requirement. Each is {sub_need_type, keyword_sentence} for keyword-matched search, or a plain string (legacy). The structured format dramatically improves accuracy.',\n ),\n constraints: z\n .object({\n deployment_model: z.enum(['self-hosted', 'cloud', 'embedded', 'serverless']).optional(),\n language: z.string().optional(),\n license: z.string().optional(),\n })\n .optional(),\n limit: z.number().int().positive().max(10).default(5),\n};\n\nexport const checkIssueSchema = {\n tool_name: z.string(),\n issue_title: z.string(),\n retry_count: z.number().int().min(0).default(0),\n docs_consulted: z.boolean().default(false),\n issue_url: z.string().url().optional(),\n};\n\nexport const checkCompatibilitySchema = {\n tool_a: z.string(),\n tool_b: z.string(),\n tool_a_version: z\n .string()\n .optional()\n .describe('Specific version of tool_a to evaluate (e.g., \"14.0.0\"). Default: latest.'),\n tool_b_version: z\n .string()\n .optional()\n .describe('Specific version of tool_b to evaluate (e.g., \"18.2.0\"). Default: latest.'),\n};\n\nexport const suggestGraphUpdateSchema = {\n suggestion_type: z.enum(['new_tool', 'new_edge', 'update_health', 'new_use_case']),\n data: z.object({\n tool_name: z.string().optional(),\n github_url: z.string().url().optional(),\n description: z.string().optional(),\n relationship: z\n .object({\n source_tool: z.string(),\n target_tool: z.string(),\n edge_type: z.enum([\n 'SOLVES',\n 'REQUIRES',\n 'INTEGRATES_WITH',\n 'REPLACES',\n 'CONFLICTS_WITH',\n 'POPULAR_WITH',\n 'BREAKS_FROM',\n 'COMPATIBLE_WITH',\n ]),\n evidence: z.string().optional(),\n })\n .optional(),\n use_case: z\n .object({\n name: z.string(),\n description: z.string(),\n tools: z.array(z.string()).optional(),\n })\n .optional(),\n }),\n query_id: z.string().uuid().optional(),\n confidence: z.number().min(0).max(1).default(0.5),\n};\n\nexport const compareToolsSchema = {\n tool_a: z.string().min(1),\n tool_b: z.string().min(1),\n use_case: z.string().optional(),\n project_config: z.string().max(100_000).optional(),\n};\n\nexport const toolcairnInitSchema = {\n agent: z.enum(['claude', 'cursor', 'windsurf', 'copilot', 'copilot-cli', 'opencode', 'generic']),\n project_root: z.string().min(1),\n server_path: z.string().optional(),\n};\n\nexport const readProjectConfigSchema = {\n project_root: z.string().min(1),\n /** When true, the response includes per-tool `locations[]`. Default false (smaller payload). */\n include_locations: z.boolean().optional(),\n};\n\nexport const updateProjectConfigSchema = {\n project_root: z.string().min(1),\n action: z.enum(['add_tool', 'remove_tool', 'update_tool', 'add_evaluation']),\n tool_name: z.string().min(1),\n data: z.record(z.string(), z.unknown()).optional(),\n};\n\nexport const classifyPromptSchema = {\n prompt: z.string().min(1).max(2000),\n project_tools: z.array(z.string()).optional(),\n};\n\nexport const verifySuggestionSchema = {\n query: z.string().min(1).max(500),\n agent_suggestions: z.array(z.string().min(1)).min(1).max(10),\n};\n\nexport const refineRequirementSchema = {\n prompt: z.string().min(1).max(2000),\n classification: z.enum([\n 'tool_discovery',\n 'stack_building',\n 'tool_comparison',\n 'tool_configuration',\n ]),\n project_context: z\n .object({\n existing_tools: z.array(z.string()).optional(),\n language: z.string().optional(),\n framework: z.string().optional(),\n })\n .optional(),\n};\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nexport function okResult(data: unknown): CallToolResult {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ ok: true, data }) }],\n };\n}\n\nexport function errResult(error: string, message: string): CallToolResult {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ ok: false, error, message }) }],\n isError: true,\n };\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:classify-prompt' });\n\n// Categories a prompt can fall into\nexport type PromptClassification =\n | 'tool_discovery' // needs to find/select tools or libraries\n | 'stack_building' // needs to compose multiple tools into a stack\n | 'tool_configuration' // already has a tool, needs setup/config help\n | 'tool_comparison' // wants to compare two or more tools\n | 'debugging' // hitting an error or unexpected behavior\n | 'general_coding'; // architecture, business logic, no tool selection needed\n\n// Categories where ToolCairn search is useful\nconst TOOL_REQUIRED_CLASSIFICATIONS: PromptClassification[] = [\n 'tool_discovery',\n 'stack_building',\n 'tool_comparison',\n];\n\nexport async function handleClassifyPrompt(args: {\n prompt: string;\n project_tools?: string[];\n}) {\n try {\n logger.info({ promptLen: args.prompt.length }, 'classify_prompt called');\n\n const projectToolsContext =\n args.project_tools && args.project_tools.length > 0\n ? `\\n\\nThe project already uses: ${args.project_tools.join(', ')}. Consider whether the prompt relates to tools already confirmed in the project.`\n : '';\n\n // Build a structured prompt the agent uses to classify\n const classification_prompt = `Classify the following developer prompt into exactly ONE of these categories:\n\nCategories:\n- tool_discovery: The developer needs to find, select, or identify a tool, library, framework, or service\n- stack_building: The developer needs to compose multiple tools together to build a complete system\n- tool_comparison: The developer wants to compare two or more specific tools\n- tool_configuration: The developer already has a tool chosen and needs help configuring or using it\n- debugging: The developer is encountering an error, bug, or unexpected behavior\n- general_coding: Architecture, business logic, algorithms — no new tool selection is needed\n\nRules:\n1. If the prompt involves building something \"from scratch\" or asks for tech stack recommendations, classify as stack_building\n2. If the prompt mentions a specific tool and asks \"should I use X or Y\", classify as tool_comparison\n3. If the prompt is about implementing features WITHOUT mentioning specific tools, classify as tool_discovery\n4. If the prompt mentions an error message, traceback, or \"not working\", classify as debugging\n5. Respond with ONLY the category name, nothing else\n\nPrompt to classify:\n\"\"\"\n${args.prompt}\n\"\"\"${projectToolsContext}\n\nYour response (one category name only):`;\n\n const needs_tool_search_prompt = `Based on this classification, determine if ToolCairn tool search should be invoked.\nRespond with 1 if the classification is one of: tool_discovery, stack_building, tool_comparison\nRespond with 0 if the classification is: tool_configuration, debugging, general_coding\nRespond with ONLY 0 or 1.`;\n\n return okResult({\n classification_prompt,\n needs_tool_search_prompt,\n valid_classifications: [\n 'tool_discovery',\n 'stack_building',\n 'tool_comparison',\n 'tool_configuration',\n 'debugging',\n 'general_coding',\n ] as PromptClassification[],\n tool_required_if: TOOL_REQUIRED_CLASSIFICATIONS,\n instructions:\n 'Step 1: Send classification_prompt to the LLM and get a classification. Step 2: If classification is in tool_required_if, call refine_requirement with the classification. Otherwise, proceed without ToolCairn search.',\n });\n } catch (e) {\n logger.error({ err: e }, 'classify_prompt failed');\n return errResult('classify_error', e instanceof Error ? e.message : String(e));\n }\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport { type PendingAuditEntry, mutateConfig } from '../config-store/index.js';\nimport { type BatchResolveFn, scanProject } from '../discovery/index.js';\nimport {\n type AgentType,\n getInstructionsForAgent,\n getMcpConfigEntry,\n getOpenCodeMcpEntry,\n} from '../templates/agent-instructions.js';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:toolcairn-init' });\n\nexport interface HandleToolcairnInitDeps {\n /** Injected resolver — the server wires this to ToolCairnClient.batchResolve. */\n batchResolve?: BatchResolveFn;\n}\n\n/**\n * One-call project setup for the ToolCairn MCP.\n *\n * Does ALL of the following server-side:\n * 1. Walks every workspace (pnpm/yarn/cargo/go-work/nx/lerna/turbo), depth-capped.\n * 2. Parses every manifest + lockfile across 12 ecosystems.\n * 3. Calls the engine batch-resolve endpoint to classify which tools are\n * indexed in the ToolCairn graph (source: \"toolcairn\") vs local-only (source: \"non_oss\").\n * 4. Detects primary languages by file-extension count.\n * 5. Detects frameworks using graph categories (primary) + offline fallback map.\n * 6. Atomically writes `.toolcairn/config.json` (v1.1 schema) + appends to\n * `.toolcairn/audit-log.jsonl`. Cross-process locked.\n *\n * Still returns `setup_steps` for the agent to execute — but ONLY for files the\n * MCP server has no business touching:\n * - CLAUDE.md / .cursorrules / etc. (user-maintained instruction docs)\n * - .mcp.json (user-maintained client config)\n * - .gitignore (user-maintained)\n */\nexport async function handleToolcairnInit(\n args: {\n agent: AgentType;\n project_root: string;\n server_path?: string;\n },\n deps: HandleToolcairnInitDeps = {},\n) {\n try {\n logger.info({ agent: args.agent, project_root: args.project_root }, 'toolcairn_init called');\n\n // 1. Programmatic scan + server-side config write.\n const scan = await scanProject(args.project_root, { batchResolve: deps.batchResolve });\n\n const audit: PendingAuditEntry = {\n action: 'init',\n tool: '__project__',\n reason: `Auto-discovered via toolcairn_init: ${scan.tools.length} tools across ${scan.scan_metadata.ecosystems_scanned.length} ecosystems`,\n };\n\n const { config, audit_entry, bootstrapped, migrated } = await mutateConfig(\n args.project_root,\n (cfg) => {\n cfg.project.name = scan.name;\n cfg.project.languages = scan.languages;\n cfg.project.frameworks = scan.frameworks;\n cfg.project.subprojects = scan.subprojects;\n // Replace the whole confirmed list — init is authoritative.\n cfg.tools.confirmed = scan.tools;\n cfg.scan_metadata = scan.scan_metadata;\n },\n audit,\n );\n\n // 2. Agent-side setup steps (instruction doc + .mcp.json + .gitignore)\n const instructions = getInstructionsForAgent(args.agent);\n const isOpenCode = args.agent === 'opencode';\n const mcpConfigEntry = isOpenCode\n ? getOpenCodeMcpEntry(args.server_path)\n : getMcpConfigEntry(args.server_path);\n const mcpConfigFile = isOpenCode ? 'opencode.json' : '.mcp.json';\n\n const mcpContent = isOpenCode\n ? JSON.stringify({ mcp: mcpConfigEntry }, null, 2)\n : JSON.stringify({ mcpServers: mcpConfigEntry }, null, 2);\n\n const setupSteps = [\n {\n step: 1,\n action: 'append-or-create',\n file: instructions.file_path,\n content: instructions.content,\n note: `Append the ToolCairn rules block to ${instructions.file_path} (or create it if missing).`,\n },\n {\n step: 2,\n action: 'merge-or-create',\n file: mcpConfigFile,\n content: mcpContent,\n note: isOpenCode\n ? `Merge the toolcairn entry into ${mcpConfigFile} under \"mcp\".`\n : `Merge the toolcairn entry into ${mcpConfigFile} under \"mcpServers\".`,\n },\n {\n step: 3,\n action: 'append',\n file: '.gitignore',\n content:\n '\\n# ToolCairn\\n.toolcairn/events.jsonl\\n.toolcairn/audit-log.jsonl\\n.toolcairn/audit-log.archive.jsonl\\n.toolcairn/config.lock\\n',\n note: 'Ignore runtime/audit files. config.json should be committed so teammates share tool intelligence.',\n },\n ];\n\n const tool_counts = {\n total: config.tools.confirmed.length,\n indexed: config.tools.confirmed.filter((t) => t.source === 'toolcairn').length,\n non_oss: config.tools.confirmed.filter((t) => t.source === 'non_oss').length,\n };\n\n return okResult({\n agent: args.agent,\n instruction_file: instructions.file_path,\n config_path: '.toolcairn/config.json',\n audit_log_path: '.toolcairn/audit-log.jsonl',\n events_path: '.toolcairn/events.jsonl',\n mcp_config_entry: mcpConfigEntry,\n setup_steps: setupSteps,\n scan_summary: {\n project_name: scan.name,\n languages: scan.languages.map((l) => ({ name: l.name, file_count: l.file_count })),\n frameworks: scan.frameworks,\n subprojects: scan.subprojects,\n tool_counts,\n warnings: scan.warnings,\n scan_metadata: scan.scan_metadata,\n },\n bootstrapped,\n migrated,\n last_audit_entry: audit_entry,\n next_steps:\n 'Config written. Apply the setup_steps above (CLAUDE.md rules + .mcp.json merge + .gitignore). Then proceed with normal tool calls — the server owns .toolcairn/ going forward.',\n });\n } catch (e) {\n logger.error({ err: e }, 'toolcairn_init failed');\n return errResult('init_error', e instanceof Error ? e.message : String(e));\n }\n}\n","export {\n AUDIT_ARCHIVE_FILE,\n AUDIT_LOG_FILE,\n CONFIG_DIR,\n CONFIG_FILE,\n joinAuditArchivePath,\n joinAuditPath,\n joinConfigDir,\n joinConfigPath,\n joinLockPath,\n LOCK_FILE,\n} from './paths.js';\nexport { readConfig, type ReadConfigResult } from './read.js';\nexport { writeConfig } from './write.js';\nexport { appendAudit, bulkAppendAudit, readLiveAudit } from './audit.js';\nexport { migrateToV1_1, type MigrateResult } from './migrate.js';\nexport { mutateConfig, type Mutator, type MutateResult, type PendingAuditEntry } from './mutate.js';\nexport { emptySkeleton } from './skeleton.js';\n","import { join } from 'node:path';\n\nexport const CONFIG_DIR = '.toolcairn';\nexport const CONFIG_FILE = 'config.json';\nexport const AUDIT_LOG_FILE = 'audit-log.jsonl';\nexport const AUDIT_ARCHIVE_FILE = 'audit-log.archive.jsonl';\nexport const LOCK_FILE = 'config.lock';\n\nexport function joinConfigDir(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR);\n}\n\nexport function joinConfigPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, CONFIG_FILE);\n}\n\nexport function joinAuditPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, AUDIT_LOG_FILE);\n}\n\nexport function joinAuditArchivePath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, AUDIT_ARCHIVE_FILE);\n}\n\nexport function joinLockPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, LOCK_FILE);\n}\n","import { readFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ToolPilotProjectConfig } from '@toolcairn/types';\nimport { fileExists } from '../discovery/util/fs.js';\nimport { CONFIG_DIR, joinConfigPath } from './paths.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:config-store' });\n\nexport interface ReadConfigResult {\n /** Parsed config, or null when config.json is absent (caller should bootstrap). */\n config: ToolPilotProjectConfig | null;\n /** Absolute path we attempted to read. */\n path: string;\n /** When parsing failed, the corrupt file is renamed here; null means no corruption. */\n corrupt_backup_path: string | null;\n}\n\n/**\n * Reads `.toolcairn/config.json` from the project root.\n *\n * - Returns `{ config: null }` when the file does not exist (no error).\n * - On JSON parse failure: renames the corrupt file to\n * `.toolcairn/config.json.corrupt.<ISO-timestamp>` and returns `{ config: null }`\n * — callers will bootstrap a fresh skeleton without clobbering recoverable data.\n */\nexport async function readConfig(projectRoot: string): Promise<ReadConfigResult> {\n const configPath = joinConfigPath(projectRoot);\n\n if (!(await fileExists(configPath))) {\n return { config: null, path: configPath, corrupt_backup_path: null };\n }\n\n let raw: string;\n try {\n raw = await readFile(configPath, 'utf-8');\n } catch (err) {\n logger.error({ err, configPath }, 'Failed to read config.json');\n throw err;\n }\n\n try {\n const parsed = JSON.parse(raw) as ToolPilotProjectConfig;\n return { config: parsed, path: configPath, corrupt_backup_path: null };\n } catch (err) {\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backup = join(projectRoot, CONFIG_DIR, `config.json.corrupt.${stamp}`);\n try {\n await rename(configPath, backup);\n logger.warn({ configPath, backup, err }, 'config.json was unparseable — moved to backup');\n } catch (renameErr) {\n logger.error({ err: renameErr, configPath, backup }, 'Failed to rename corrupt config.json');\n }\n return { config: null, path: configPath, corrupt_backup_path: backup };\n }\n}\n","import { access, readdir, stat } from 'node:fs/promises';\n\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function isDir(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** Directories that discovery + language-detect never descend into. */\nexport const IGNORED_DIRS = new Set([\n 'node_modules',\n '.git',\n '.hg',\n '.svn',\n 'dist',\n 'build',\n 'out',\n '.next',\n '.turbo',\n '.nuxt',\n 'target', // rust, java\n 'vendor', // go, ruby, composer\n '__pycache__',\n '.venv',\n 'venv',\n '.tox',\n '.pytest_cache',\n '.mypy_cache',\n 'bin',\n 'obj', // dotnet\n '.gradle',\n '.idea',\n '.vscode',\n '.DS_Store',\n 'coverage',\n '.cache',\n '.pnpm-store',\n]);\n\n/** Yields absolute paths of every dir the walker should consider. */\nexport async function* walkDirs(root: string, maxDepth = 6): AsyncGenerator<string> {\n yield root;\n yield* walkDirsInner(root, 0, maxDepth);\n}\n\nasync function* walkDirsInner(\n dir: string,\n depth: number,\n maxDepth: number,\n): AsyncGenerator<string> {\n if (depth >= maxDepth) return;\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n if (entry.name.startsWith('.') && !['.github', '.claude', '.toolcairn'].includes(entry.name)) {\n continue;\n }\n const full = `${dir}/${entry.name}`;\n yield full;\n yield* walkDirsInner(full, depth + 1, maxDepth);\n }\n}\n","import { mkdir } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ToolPilotProjectConfig } from '@toolcairn/types';\nimport writeFileAtomic from 'write-file-atomic';\nimport { joinConfigDir, joinConfigPath } from './paths.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:config-store' });\n\n/**\n * Atomically writes config.json.\n *\n * Uses `write-file-atomic` which:\n * - Writes to a same-dir temp file (avoids EXDEV on different volumes).\n * - fsyncs the temp file and the parent directory (crash-safe).\n * - Renames to the target (overwrites on Windows via MoveFileExW).\n * - Retries automatically on EBUSY/EPERM (Windows AV handle contention).\n *\n * Caller MUST hold the cross-process lock — see mutate.ts.\n */\nexport async function writeConfig(\n projectRoot: string,\n config: ToolPilotProjectConfig,\n): Promise<void> {\n // Ensure .toolcairn/ exists (no-op after first write, cheap).\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n\n const configPath = joinConfigPath(projectRoot);\n const serialised = `${JSON.stringify(config, null, 2)}\\n`;\n\n await writeFileAtomic(configPath, serialised);\n logger.debug({ configPath, bytes: serialised.length }, 'config.json written atomically');\n}\n","import { appendFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfigAuditEntry } from '@toolcairn/types';\nimport writeFileAtomic from 'write-file-atomic';\nimport { fileExists } from '../discovery/util/fs.js';\nimport { joinAuditArchivePath, joinAuditPath, joinConfigDir } from './paths.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:audit-log' });\n\n/** Maximum entries retained in the live audit-log.jsonl before FIFO archive. */\nconst MAX_LIVE_ENTRIES = 1000;\n/** Entries moved to the archive when the live file exceeds MAX_LIVE_ENTRIES. */\nconst ARCHIVE_BATCH = 500;\n\n/**\n * Appends one entry to `.toolcairn/audit-log.jsonl`, creating the file if absent.\n *\n * After append, if the live file has grown beyond MAX_LIVE_ENTRIES, the oldest\n * ARCHIVE_BATCH lines are moved to `.toolcairn/audit-log.archive.jsonl` and the\n * live file is truncated to the remaining tail.\n *\n * Caller MUST hold the cross-process lock.\n */\nexport async function appendAudit(projectRoot: string, entry: ConfigAuditEntry): Promise<void> {\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n const auditPath = joinAuditPath(projectRoot);\n const line = `${JSON.stringify(entry)}\\n`;\n await appendFile(auditPath, line, 'utf-8');\n\n // Rotation check — counts lines in-place; cheap for files under a few MB.\n await rotateIfNeeded(projectRoot, auditPath);\n}\n\n/**\n * Bulk-appends many entries in one flush. Used during 1.0 → 1.1 migration when\n * the legacy `audit_log[]` is relocated into the jsonl file.\n */\nexport async function bulkAppendAudit(\n projectRoot: string,\n entries: ConfigAuditEntry[],\n): Promise<void> {\n if (entries.length === 0) return;\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n const auditPath = joinAuditPath(projectRoot);\n const payload = entries.map((e) => `${JSON.stringify(e)}\\n`).join('');\n await appendFile(auditPath, payload, 'utf-8');\n await rotateIfNeeded(projectRoot, auditPath);\n}\n\n/** Returns all audit entries in the live file (not the archive). Parse errors are skipped. */\nexport async function readLiveAudit(projectRoot: string): Promise<ConfigAuditEntry[]> {\n const auditPath = joinAuditPath(projectRoot);\n if (!(await fileExists(auditPath))) return [];\n const raw = await readFile(auditPath, 'utf-8');\n return parseJsonl(raw);\n}\n\nasync function rotateIfNeeded(projectRoot: string, auditPath: string): Promise<void> {\n const raw = await readFile(auditPath, 'utf-8');\n const lines = raw.split('\\n').filter((l) => l.trim().length > 0);\n if (lines.length <= MAX_LIVE_ENTRIES) return;\n\n const archiveBatch = lines.slice(0, ARCHIVE_BATCH);\n const keep = lines.slice(ARCHIVE_BATCH);\n const archivePath = joinAuditArchivePath(projectRoot);\n\n try {\n // Archive append (never truncates) — then atomic-write the truncated live file.\n await appendFile(archivePath, `${archiveBatch.join('\\n')}\\n`, 'utf-8');\n // Atomic truncate by writing new content to a temp + rename.\n const newContent = `${keep.join('\\n')}\\n`;\n await writeFileAtomic(auditPath, newContent);\n logger.info(\n { archived: archiveBatch.length, retained: keep.length },\n 'audit-log.jsonl rotated',\n );\n } catch (err) {\n logger.warn({ err, auditPath, archivePath }, 'Audit-log rotation failed — live file intact');\n }\n}\n\nfunction parseJsonl(raw: string): ConfigAuditEntry[] {\n const out: ConfigAuditEntry[] = [];\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue;\n try {\n out.push(JSON.parse(line) as ConfigAuditEntry);\n } catch {\n // Skip malformed line — do not break the caller\n }\n }\n return out;\n}\n\n/** Test helper — blow away the audit log files. Not exported from the barrel. */\nexport async function _resetAudit(projectRoot: string): Promise<void> {\n for (const p of [joinAuditPath(projectRoot), joinAuditArchivePath(projectRoot)]) {\n try {\n await rm(p);\n } catch {\n /* ignore */\n }\n }\n // Re-create empty live file so fresh appends start clean.\n try {\n await writeFile(joinAuditPath(projectRoot), '', 'utf-8');\n } catch {\n /* ignore */\n }\n}\n","import type { ConfigAuditEntry, ToolPilotProjectConfig } from '@toolcairn/types';\nimport { bulkAppendAudit } from './audit.js';\n\nexport interface MigrateResult {\n migrated: boolean;\n /** True iff the doc was at version 1.0 and was upgraded in place. */\n was_v1_0: boolean;\n /** Legacy audit entries that were moved out of the config into audit-log.jsonl. */\n legacy_audit_entries: ConfigAuditEntry[];\n}\n\n/**\n * Migrates a parsed config in place from v1.0 to v1.1.\n *\n * - Promotes `project.language` (string) to `project.languages` (array).\n * - Promotes `project.framework` (string) to `project.frameworks` (array).\n * - Ensures every ConfirmedTool has `locations: []` (empty by default — re-scan\n * fills in accurate data on the first toolcairn_init after upgrade).\n * - Relocates inline `audit_log[]` into audit-log.jsonl and drops the field from\n * the in-memory config.\n *\n * Does NOT write to disk — caller (mutate.ts) is responsible for the atomic write\n * and for bulk-appending the returned `legacy_audit_entries` to audit-log.jsonl.\n */\nexport async function migrateToV1_1(\n config: ToolPilotProjectConfig,\n projectRoot: string,\n): Promise<MigrateResult> {\n if (config.version === '1.1') {\n // Already on target schema — just make sure locations[] exists so handlers\n // can rely on it being present.\n for (const tool of config.tools.confirmed) {\n if (!tool.locations) tool.locations = [];\n }\n return { migrated: false, was_v1_0: false, legacy_audit_entries: [] };\n }\n\n // Upgrade project metadata.\n if (!config.project.languages) {\n config.project.languages = config.project.language\n ? [{ name: config.project.language, file_count: 0, workspaces: ['.'] }]\n : [];\n }\n if (!config.project.frameworks) {\n config.project.frameworks = config.project.framework\n ? [\n {\n name: config.project.framework,\n ecosystem: 'npm',\n workspace: '.',\n source: 'local',\n },\n ]\n : [];\n }\n if (!config.project.subprojects) config.project.subprojects = [];\n\n // Every ConfirmedTool gets a locations[] (empty placeholder — first re-scan fills it).\n for (const tool of config.tools.confirmed) {\n if (!tool.locations) tool.locations = [];\n }\n\n // Extract legacy audit entries + append migration marker.\n const legacy = config.audit_log ?? [];\n delete config.audit_log;\n\n const now = new Date().toISOString();\n const migrationEntry: ConfigAuditEntry = {\n action: 'migrate',\n tool: '__schema__',\n timestamp: now,\n reason:\n 'Schema 1.0 → 1.1: audit_log relocated to audit-log.jsonl; languages/frameworks expanded to arrays',\n };\n config.last_audit_entry = migrationEntry;\n config.version = '1.1';\n\n // Persist legacy entries + the migration entry into the audit-log.jsonl file.\n // (The mutate.ts orchestration still holds the cross-process lock at this point.)\n await bulkAppendAudit(projectRoot, [...legacy, migrationEntry]);\n\n return { migrated: true, was_v1_0: true, legacy_audit_entries: legacy };\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfigAuditEntry, ToolPilotProjectConfig } from '@toolcairn/types';\nimport lockfile from 'proper-lockfile';\nimport { fileExists } from '../discovery/util/fs.js';\nimport { appendAudit } from './audit.js';\nimport { migrateToV1_1 } from './migrate.js';\nimport { joinConfigDir, joinConfigPath } from './paths.js';\nimport { readConfig } from './read.js';\nimport { emptySkeleton } from './skeleton.js';\nimport { writeConfig } from './write.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:config-store' });\n\nexport type Mutator = (config: ToolPilotProjectConfig) => void | Promise<void>;\n\n/** The audit entry to attach, sans timestamp (mutate.ts stamps it). */\nexport type PendingAuditEntry = Omit<ConfigAuditEntry, 'timestamp'>;\n\nexport interface MutateResult {\n config: ToolPilotProjectConfig;\n audit_entry: ConfigAuditEntry;\n /** True iff we bootstrapped a fresh config.json on this call. */\n bootstrapped: boolean;\n /** True iff the config on disk was v1.0 and was migrated in the same write. */\n migrated: boolean;\n}\n\n/**\n * The single supported entry point for mutating `.toolcairn/config.json`.\n *\n * Flow (under cross-process advisory lock):\n * 1. Ensure `.toolcairn/` exists + acquire `.toolcairn/config.lock`.\n * 2. Read config.json (or bootstrap a fresh v1.1 skeleton if absent).\n * 3. If schema is v1.0, migrate in place and relocate legacy audit entries.\n * 4. Apply the caller-supplied `mutator(config)` on the in-memory object.\n * 5. Stamp `{...audit, timestamp: now}` into `config.last_audit_entry`.\n * 6. Atomic-write `config.json` (write-file-atomic: fsync + parent dirsync + EBUSY retry).\n * 7. Append the audit entry to `.toolcairn/audit-log.jsonl` (FIFO-archives at 1000 entries).\n * 8. Release the lock.\n *\n * The lock survives process crashes (stale-lock timeout = 10s); if a prior holder\n * crashed mid-write, the write-file-atomic temp file is naturally cleaned up by a\n * subsequent run.\n */\nexport async function mutateConfig(\n projectRoot: string,\n mutator: Mutator,\n audit: PendingAuditEntry,\n): Promise<MutateResult> {\n // proper-lockfile locks a real file by creating `<file>.lock/` directory.\n // We lock config.json itself (idiomatic), seeding an empty skeleton first when absent.\n // Record whether the real config.json existed BEFORE we seeded anything — the\n // \"bootstrapped\" flag we return reflects that pre-seed state.\n const configPath = joinConfigPath(projectRoot);\n const preExisted = await fileExists(configPath);\n await ensureLockableDir(projectRoot);\n\n const release = await lockfile.lock(configPath, {\n stale: 10_000,\n retries: { retries: 5, minTimeout: 50, factor: 2, maxTimeout: 500 },\n realpath: false,\n });\n\n try {\n // 1. Read\n const { config: existing } = await readConfig(projectRoot);\n let config: ToolPilotProjectConfig;\n const bootstrapped = !preExisted;\n let migrated = false;\n\n if (!existing) {\n config = emptySkeleton();\n logger.info({ projectRoot }, 'Bootstrapping fresh .toolcairn/config.json');\n } else {\n config = existing;\n }\n\n // 2. Migrate if needed (before mutator so mutators see the v1.1 shape).\n if (config.version === '1.0') {\n const result = await migrateToV1_1(config, projectRoot);\n migrated = result.migrated;\n } else {\n // Ensure v1.1 invariants even if the file was hand-edited\n for (const tool of config.tools.confirmed) {\n if (!tool.locations) tool.locations = [];\n }\n if (!config.project.languages) config.project.languages = [];\n if (!config.project.frameworks) config.project.frameworks = [];\n if (!config.project.subprojects) config.project.subprojects = [];\n }\n\n // 3. Caller mutation.\n await mutator(config);\n\n // 4. Stamp audit entry.\n const now = new Date().toISOString();\n const entry: ConfigAuditEntry = { ...audit, timestamp: now };\n config.last_audit_entry = entry;\n config.version = '1.1';\n\n // 5. Atomic write + audit append.\n await writeConfig(projectRoot, config);\n await appendAudit(projectRoot, entry);\n\n return { config, audit_entry: entry, bootstrapped, migrated };\n } finally {\n try {\n await release();\n } catch (err) {\n logger.warn({ err, configPath }, 'Failed to release config lock — may be stale');\n }\n }\n}\n\n/**\n * proper-lockfile requires the lock target to exist on disk. For first-time\n * runs we seed an empty v1.1 skeleton; subsequent runs no-op.\n */\nasync function ensureLockableDir(projectRoot: string): Promise<void> {\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n\n const configPath = joinConfigPath(projectRoot);\n if (!(await fileExists(configPath))) {\n try {\n await writeFile(configPath, `${JSON.stringify(emptySkeleton(), null, 2)}\\n`, 'utf-8');\n } catch (err) {\n // Tolerable — another process may have seeded concurrently.\n logger.debug({ err, configPath }, 'Bootstrap seed skipped (likely race)');\n }\n }\n}\n","import type { ToolPilotProjectConfig } from '@toolcairn/types';\n\n/** A fresh, empty v1.1 config. Used when bootstrapping a project for the first time. */\nexport function emptySkeleton(name = ''): ToolPilotProjectConfig {\n return {\n version: '1.1',\n project: {\n name,\n languages: [],\n frameworks: [],\n subprojects: [],\n },\n tools: {\n confirmed: [],\n pending_evaluation: [],\n },\n last_audit_entry: null,\n };\n}\n","export { scanProject } from './scan-project.js';\nexport type {\n BatchResolveFn,\n ScanProjectOptions,\n ScanProjectResult,\n} from './scan-project.js';\nexport type { BatchResolveResult } from './frameworks/detect.js';\nexport type { DetectedTool, ParseResult, Parser, ParserInput } from './types.js';\n","import { readFile } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type {\n ConfirmedTool,\n DiscoveryWarning,\n Ecosystem,\n MatchMethod,\n ProjectFramework,\n ProjectLanguage,\n ProjectSubproject,\n ScanMetadata,\n ToolLocation,\n ToolSource,\n} from '@toolcairn/types';\nimport { detectEcosystems } from './ecosystem-detect.js';\nimport { type BatchResolveResult, detectFrameworks } from './frameworks/detect.js';\nimport { detectLanguages } from './language-detect.js';\nimport { PARSERS } from './parsers/index.js';\nimport type { DetectedTool } from './types.js';\nimport { fileExists } from './util/fs.js';\nimport { toRelPosix } from './workspaces/glob.js';\nimport { discoverWorkspaces } from './workspaces/walker.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:scan-project' });\n\n/** Resolver signature — the MCP handler injects a function backed by @toolcairn/remote. */\nexport type BatchResolveFn = (items: Array<{ name: string; ecosystem: Ecosystem }>) => Promise<{\n results: BatchResolveResult[];\n warnings: DiscoveryWarning[];\n /** Match methods per resolved entry (keyed by \"ecosystem:name\"). */\n methods: Map<string, MatchMethod>;\n /** GitHub urls per resolved entry (keyed by \"ecosystem:name\"). */\n githubUrls: Map<string, string>;\n}>;\n\nexport interface ScanProjectOptions {\n /** Injected resolver. Omit to run in offline-only mode (all tools → non_oss). */\n batchResolve?: BatchResolveFn;\n /** Maximum workspace-recursion depth. */\n maxDepth?: number;\n}\n\nexport interface ScanProjectResult {\n name: string;\n languages: ProjectLanguage[];\n frameworks: ProjectFramework[];\n subprojects: ProjectSubproject[];\n /** Tools shaped for direct insertion into `config.tools.confirmed`. */\n tools: ConfirmedTool[];\n warnings: DiscoveryWarning[];\n scan_metadata: ScanMetadata;\n}\n\n/**\n * Scan a project root and return everything needed to populate a v1.1 config.\n *\n * Steps:\n * 1. Discover all workspace roots (depth-capped recursive walk).\n * 2. For each workspace, detect ecosystems via manifest presence.\n * 3. Parse every (workspace, ecosystem) pair in parallel.\n * 4. Merge duplicate tools across workspaces into one ConfirmedTool with locations[].\n * 5. Detect languages (file-extension counts excluding vendor/build dirs).\n * 6. Call batchResolve to classify each (ecosystem, name) against the ToolCairn graph.\n * 7. Build frameworks[] using the batch-resolve categories + local fallback.\n */\nexport async function scanProject(\n projectRoot: string,\n options: ScanProjectOptions = {},\n): Promise<ScanProjectResult> {\n const start = Date.now();\n const { batchResolve, maxDepth = 5 } = options;\n const absRoot = resolve(projectRoot);\n const warnings: DiscoveryWarning[] = [];\n\n logger.info({ projectRoot: absRoot }, 'Starting project scan');\n\n // --- 1. Workspace discovery --------------------------------------------\n const { paths: workspaceAbs, warnings: wsWarnings } = await discoverWorkspaces(absRoot, maxDepth);\n warnings.push(...wsWarnings);\n\n // --- 2+3. Per-workspace per-ecosystem parsing --------------------------\n const allDetected: DetectedTool[] = [];\n const ecosystemsScanned = new Set<Ecosystem>();\n const parsersFailed: string[] = [];\n const subprojects: ProjectSubproject[] = [];\n\n // Run all parser invocations concurrently — they're pure file reads.\n const parseTasks: Promise<void>[] = [];\n for (const wsDir of workspaceAbs) {\n const wsRel = toRelPosix(absRoot, wsDir);\n const ecosystems = await detectEcosystems(wsDir);\n for (const eco of ecosystems) {\n ecosystemsScanned.add(eco);\n const parser = PARSERS[eco];\n parseTasks.push(\n parser({ workspace_dir: wsDir, workspace_rel: wsRel, project_root: absRoot })\n .then((result) => {\n allDetected.push(...result.tools);\n warnings.push(...result.warnings);\n if (result.tools.length > 0 && wsRel !== '') {\n // Track non-root workspaces that actually had tools under an ecosystem\n const existing = subprojects.find((s) => s.path === wsRel && s.ecosystem === eco);\n if (!existing) {\n subprojects.push({\n path: wsRel,\n manifest: primaryManifestForEcosystem(eco),\n ecosystem: eco,\n });\n }\n }\n })\n .catch((err: unknown) => {\n parsersFailed.push(`${eco}@${wsRel || '.'}`);\n warnings.push({\n scope: `parser:${eco}`,\n path: wsRel || '.',\n message: `Parser crashed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }),\n );\n }\n }\n await Promise.all(parseTasks);\n\n // --- 4. Merge dedupe by (ecosystem, name) → locations[] ---------------\n const mergedMap = new Map<\n string,\n { name: string; ecosystem: Ecosystem; locations: ToolLocation[] }\n >();\n for (const dep of allDetected) {\n const key = `${dep.ecosystem}:${dep.name}`;\n const location: ToolLocation = {\n workspace_path: dep.workspace_path,\n manifest_file: dep.manifest_file,\n section: dep.section,\n ecosystem: dep.ecosystem,\n version_constraint: dep.version_constraint,\n resolved_version: dep.resolved_version,\n };\n const existing = mergedMap.get(key);\n if (existing) {\n // Avoid dupe-location when the same parser picks up the same dep twice\n const sameLoc = existing.locations.some(\n (l) =>\n l.workspace_path === location.workspace_path &&\n l.manifest_file === location.manifest_file &&\n l.section === location.section,\n );\n if (!sameLoc) existing.locations.push(location);\n } else {\n mergedMap.set(key, { name: dep.name, ecosystem: dep.ecosystem, locations: [location] });\n }\n }\n\n // --- 5. Language detection ---------------------------------------------\n const workspaceRels = workspaceAbs.map((abs) => toRelPosix(absRoot, abs));\n const languages = await detectLanguages(absRoot, workspaceRels);\n\n // --- 6. Batch-resolve against the graph -------------------------------\n const resolveInputs = [...mergedMap.values()].map(({ name, ecosystem }) => ({ name, ecosystem }));\n const resolved = new Map<string, BatchResolveResult>();\n const methods = new Map<string, MatchMethod>();\n const githubUrls = new Map<string, string>();\n\n if (batchResolve && resolveInputs.length > 0) {\n try {\n const r = await batchResolve(resolveInputs);\n for (const res of r.results) {\n const key = `${res.input.ecosystem}:${res.input.name}`;\n resolved.set(key, res);\n }\n for (const [k, v] of r.methods) methods.set(k, v);\n for (const [k, v] of r.githubUrls) githubUrls.set(k, v);\n warnings.push(...r.warnings);\n } catch (err) {\n warnings.push({\n scope: 'batch-resolve',\n message: `Failed to resolve tools against graph: ${err instanceof Error ? err.message : String(err)}. Falling back to local classification.`,\n });\n }\n } else if (!batchResolve) {\n warnings.push({\n scope: 'batch-resolve',\n message:\n 'No batchResolve client provided — running in offline-only mode; all tools classified as non_oss.',\n });\n }\n\n // --- 7. Framework detection --------------------------------------------\n const frameworks = detectFrameworks(allDetected, resolved);\n\n // --- 8. Assemble ConfirmedTool[] --------------------------------------\n const now = new Date().toISOString();\n const confirmed: ConfirmedTool[] = [];\n let toolsResolvedCount = 0;\n\n for (const { name, ecosystem, locations } of mergedMap.values()) {\n const key = `${ecosystem}:${name}`;\n const graph = resolved.get(key);\n const matchMethod = methods.get(key) ?? 'none';\n const matched = graph?.matched === true;\n if (matched) toolsResolvedCount++;\n\n const source: ToolSource = matched ? 'toolcairn' : 'non_oss';\n const canonical = graph?.tool?.canonical_name;\n const categories = graph?.tool?.categories;\n const github_url = githubUrls.get(key);\n const version =\n locations.find((l) => l.resolved_version)?.resolved_version ??\n locations[0]?.version_constraint;\n\n confirmed.push({\n name,\n source,\n github_url,\n version,\n chosen_at: now,\n chosen_reason: 'Auto-detected from manifest during toolcairn_init scan',\n alternatives_considered: [],\n canonical_name: canonical,\n categories,\n match_method: matchMethod,\n locations,\n });\n }\n // Stable order: indexed first (alphabetical), then non-indexed (alphabetical)\n confirmed.sort((a, b) => {\n const rank = (t: ConfirmedTool) => (t.source === 'toolcairn' ? 0 : 1);\n if (rank(a) !== rank(b)) return rank(a) - rank(b);\n return a.name.localeCompare(b.name);\n });\n\n // Sort subprojects by path for deterministic output\n subprojects.sort((a, b) => a.path.localeCompare(b.path));\n\n const name = await inferProjectName(absRoot);\n const scan_metadata: ScanMetadata = {\n ecosystems_scanned: [...ecosystemsScanned].sort(),\n parsers_failed: parsersFailed.sort(),\n tools_resolved: toolsResolvedCount,\n tools_unresolved: confirmed.length - toolsResolvedCount,\n duration_ms: Date.now() - start,\n completed_at: now,\n };\n\n logger.info(\n {\n projectRoot: absRoot,\n workspaces: workspaceAbs.length,\n ecosystems: scan_metadata.ecosystems_scanned,\n tools: confirmed.length,\n resolved: toolsResolvedCount,\n languages: languages.map((l) => l.name),\n frameworks: frameworks.map((f) => f.name),\n duration_ms: scan_metadata.duration_ms,\n },\n 'Project scan complete',\n );\n\n return {\n name,\n languages,\n frameworks,\n subprojects,\n tools: confirmed,\n warnings,\n scan_metadata,\n };\n}\n\nfunction primaryManifestForEcosystem(ecosystem: Ecosystem): string {\n switch (ecosystem) {\n case 'npm':\n return 'package.json';\n case 'pypi':\n return 'pyproject.toml';\n case 'cargo':\n return 'Cargo.toml';\n case 'go':\n return 'go.mod';\n case 'rubygems':\n return 'Gemfile';\n case 'maven':\n return 'pom.xml';\n case 'gradle':\n return 'build.gradle';\n case 'composer':\n return 'composer.json';\n case 'hex':\n return 'mix.exs';\n case 'pub':\n return 'pubspec.yaml';\n case 'nuget':\n return '*.csproj';\n case 'swift-pm':\n return 'Package.swift';\n }\n}\n\nasync function inferProjectName(projectRoot: string): Promise<string> {\n // Prefer package.json#name, then Cargo.toml [package].name, then pyproject.toml [project].name.\n const pkgPath = resolve(projectRoot, 'package.json');\n if (await fileExists(pkgPath)) {\n try {\n const doc = JSON.parse(await readFile(pkgPath, 'utf-8')) as { name?: string };\n if (doc.name) return doc.name;\n } catch {\n /* non-fatal */\n }\n }\n return basename(projectRoot);\n}\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Ecosystem } from '@toolcairn/types';\nimport { fileExists } from './util/fs.js';\n\n/** Manifest presence → ecosystem. Lockfile or manifest either triggers detection. */\nconst ECOSYSTEM_MANIFESTS: Record<Ecosystem, string[]> = {\n npm: ['package.json'],\n pypi: ['pyproject.toml', 'requirements.txt', 'requirements-dev.txt', 'setup.py', 'Pipfile'],\n cargo: ['Cargo.toml'],\n go: ['go.mod'],\n rubygems: ['Gemfile'],\n maven: ['pom.xml'],\n gradle: ['build.gradle', 'build.gradle.kts', 'gradle.lockfile'],\n composer: ['composer.json'],\n hex: ['mix.exs'],\n pub: ['pubspec.yaml'],\n nuget: ['packages.config'],\n 'swift-pm': ['Package.swift'],\n};\n\n/** Any file extension that pattern-matches an ecosystem (e.g. *.csproj for nuget). */\nconst ECOSYSTEM_EXTENSIONS: Record<string, Ecosystem> = {\n '.csproj': 'nuget',\n '.fsproj': 'nuget',\n};\n\n/**\n * Detect which ecosystems have manifests in the given directory.\n * Does not recurse — caller invokes per workspace.\n */\nexport async function detectEcosystems(workspaceDir: string): Promise<Ecosystem[]> {\n const found = new Set<Ecosystem>();\n\n // Check well-known filenames\n for (const [ecosystem, files] of Object.entries(ECOSYSTEM_MANIFESTS) as Array<\n [Ecosystem, string[]]\n >) {\n for (const file of files) {\n if (await fileExists(join(workspaceDir, file))) {\n found.add(ecosystem);\n break;\n }\n }\n }\n\n // Check extension patterns (e.g. *.csproj)\n try {\n const entries = await readdir(workspaceDir);\n for (const entry of entries) {\n for (const [ext, ecosystem] of Object.entries(ECOSYSTEM_EXTENSIONS)) {\n if (entry.endsWith(ext)) {\n found.add(ecosystem);\n break;\n }\n }\n }\n } catch {\n // unreadable dir — skip\n }\n\n return Array.from(found);\n}\n","import type { Ecosystem, ProjectFramework } from '@toolcairn/types';\nimport type { DetectedTool } from '../types.js';\n\n/**\n * Offline framework-detection map — primary signal is the engine batch-resolve\n * `categories` array; this is the fallback for tools not in the graph, or when\n * the engine is unreachable.\n */\nconst FALLBACK: Record<Ecosystem, Record<string, string>> = {\n npm: {\n next: 'Next.js',\n react: 'React',\n vue: 'Vue',\n nuxt: 'Nuxt',\n svelte: 'Svelte',\n '@sveltejs/kit': 'SvelteKit',\n astro: 'Astro',\n 'solid-js': 'SolidJS',\n express: 'Express',\n fastify: 'Fastify',\n koa: 'Koa',\n hono: 'Hono',\n '@nestjs/core': 'NestJS',\n remix: 'Remix',\n '@remix-run/react': 'Remix',\n gatsby: 'Gatsby',\n electron: 'Electron',\n 'react-native': 'React Native',\n expo: 'Expo',\n angular: 'Angular',\n '@angular/core': 'Angular',\n turbo: 'Turborepo',\n nx: 'Nx',\n vite: 'Vite',\n webpack: 'Webpack',\n },\n pypi: {\n django: 'Django',\n flask: 'Flask',\n fastapi: 'FastAPI',\n starlette: 'Starlette',\n pyramid: 'Pyramid',\n tornado: 'Tornado',\n aiohttp: 'aiohttp',\n litestar: 'Litestar',\n sanic: 'Sanic',\n bottle: 'Bottle',\n quart: 'Quart',\n celery: 'Celery',\n streamlit: 'Streamlit',\n gradio: 'Gradio',\n torch: 'PyTorch',\n tensorflow: 'TensorFlow',\n transformers: 'Transformers',\n langchain: 'LangChain',\n 'llama-index': 'LlamaIndex',\n },\n cargo: {\n 'actix-web': 'Actix Web',\n axum: 'Axum',\n rocket: 'Rocket',\n warp: 'Warp',\n tide: 'Tide',\n poem: 'Poem',\n salvo: 'Salvo',\n leptos: 'Leptos',\n dioxus: 'Dioxus',\n yew: 'Yew',\n tauri: 'Tauri',\n bevy: 'Bevy',\n tokio: 'Tokio',\n },\n go: {\n 'github.com/gin-gonic/gin': 'Gin',\n 'github.com/labstack/echo': 'Echo',\n 'github.com/labstack/echo/v4': 'Echo',\n 'github.com/gofiber/fiber': 'Fiber',\n 'github.com/gofiber/fiber/v2': 'Fiber',\n 'github.com/beego/beego': 'Beego',\n 'github.com/go-chi/chi': 'Chi',\n 'github.com/gorilla/mux': 'Gorilla',\n 'github.com/revel/revel': 'Revel',\n },\n rubygems: {\n rails: 'Ruby on Rails',\n sinatra: 'Sinatra',\n hanami: 'Hanami',\n roda: 'Roda',\n rack: 'Rack',\n },\n maven: {\n 'org.springframework.boot:spring-boot-starter': 'Spring Boot',\n 'org.springframework.boot:spring-boot-starter-web': 'Spring Boot',\n 'io.quarkus:quarkus-core': 'Quarkus',\n 'io.micronaut:micronaut-core': 'Micronaut',\n 'io.vertx:vertx-core': 'Vert.x',\n 'com.google.inject:guice': 'Guice',\n },\n gradle: {\n 'org.springframework.boot:spring-boot-starter': 'Spring Boot',\n 'io.quarkus:quarkus-core': 'Quarkus',\n 'io.micronaut:micronaut-core': 'Micronaut',\n 'io.ktor:ktor-server-core': 'Ktor',\n },\n composer: {\n 'laravel/framework': 'Laravel',\n 'symfony/framework-bundle': 'Symfony',\n 'cakephp/cakephp': 'CakePHP',\n 'yiisoft/yii2': 'Yii',\n 'slim/slim': 'Slim',\n },\n hex: {\n phoenix: 'Phoenix',\n ecto: 'Ecto',\n nerves: 'Nerves',\n ash: 'Ash',\n },\n pub: {\n flutter: 'Flutter',\n flutter_bloc: 'Flutter BLoC',\n },\n nuget: {\n 'Microsoft.AspNetCore.App': 'ASP.NET Core',\n 'Microsoft.AspNetCore': 'ASP.NET Core',\n 'Microsoft.EntityFrameworkCore': 'Entity Framework Core',\n 'Microsoft.NET.Sdk.Web': 'ASP.NET Core',\n Avalonia: 'Avalonia',\n MAUI: '.NET MAUI',\n },\n 'swift-pm': {\n vapor: 'Vapor',\n kitura: 'Kitura',\n perfect: 'Perfect',\n },\n};\n\n/** Categories that indicate \"this IS a framework\" when returned by batch-resolve. */\nconst FRAMEWORK_CATEGORIES = new Set([\n 'framework',\n 'web-framework',\n 'ui-framework',\n 'meta-framework',\n 'backend-framework',\n 'frontend-framework',\n 'mobile-framework',\n]);\n\nexport interface BatchResolveResult {\n input: { name: string; ecosystem: Ecosystem };\n matched: boolean;\n tool?: { canonical_name: string; categories: string[] };\n}\n\n/**\n * Build the frameworks[] array for config.json.\n *\n * Primary signal: batch-resolve response carries a `categories` array with a\n * framework-like tag — use graph-resolved canonical name and tag source='graph'.\n * Fallback (offline or non-indexed): check FALLBACK[ecosystem][name] and tag\n * source='local'.\n *\n * De-duplicates by (framework_name, workspace). Dev-dependencies are ignored\n * (a dev-dep is almost never \"the framework\").\n */\nexport function detectFrameworks(\n tools: DetectedTool[],\n resolved: Map<string, BatchResolveResult>,\n): ProjectFramework[] {\n const out: ProjectFramework[] = [];\n const seen = new Set<string>();\n\n for (const tool of tools) {\n if (tool.section === 'dev') continue;\n const workspace = tool.workspace_path || '.';\n const resolvedKey = `${tool.ecosystem}:${tool.name}`;\n const graphMatch = resolved.get(resolvedKey);\n\n let frameworkName: string | null = null;\n let source: 'graph' | 'local' = 'local';\n\n if (graphMatch?.matched && graphMatch.tool) {\n const categories = graphMatch.tool.categories ?? [];\n if (categories.some((c) => FRAMEWORK_CATEGORIES.has(c.toLowerCase()))) {\n frameworkName = graphMatch.tool.canonical_name;\n source = 'graph';\n }\n }\n\n if (!frameworkName) {\n const localName = FALLBACK[tool.ecosystem]?.[tool.name];\n if (localName) {\n frameworkName = localName;\n source = 'local';\n }\n }\n\n if (!frameworkName) continue;\n const dedupeKey = `${frameworkName}:${workspace}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n\n out.push({\n name: frameworkName,\n ecosystem: tool.ecosystem,\n workspace,\n source,\n });\n }\n\n return out;\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport type { ProjectLanguage } from '@toolcairn/types';\nimport { IGNORED_DIRS } from './util/fs.js';\n\n/** File extension → language name. Only extensions with clear 1:1 mapping. */\nconst EXT_TO_LANGUAGE: Record<string, string> = {\n '.ts': 'TypeScript',\n '.tsx': 'TypeScript',\n '.js': 'JavaScript',\n '.jsx': 'JavaScript',\n '.mjs': 'JavaScript',\n '.cjs': 'JavaScript',\n '.py': 'Python',\n '.pyi': 'Python',\n '.rs': 'Rust',\n '.go': 'Go',\n '.rb': 'Ruby',\n '.java': 'Java',\n '.kt': 'Kotlin',\n '.kts': 'Kotlin',\n '.scala': 'Scala',\n '.php': 'PHP',\n '.ex': 'Elixir',\n '.exs': 'Elixir',\n '.erl': 'Erlang',\n '.dart': 'Dart',\n '.cs': 'C#',\n '.fs': 'F#',\n '.vb': 'Visual Basic',\n '.swift': 'Swift',\n '.c': 'C',\n '.h': 'C',\n '.cpp': 'C++',\n '.cxx': 'C++',\n '.cc': 'C++',\n '.hpp': 'C++',\n '.m': 'Objective-C',\n '.mm': 'Objective-C',\n '.lua': 'Lua',\n '.r': 'R',\n '.jl': 'Julia',\n '.nim': 'Nim',\n '.zig': 'Zig',\n '.clj': 'Clojure',\n '.cljs': 'Clojure',\n '.hs': 'Haskell',\n '.elm': 'Elm',\n '.ml': 'OCaml',\n '.mli': 'OCaml',\n '.vue': 'Vue',\n '.svelte': 'Svelte',\n '.astro': 'Astro',\n};\n\n/**\n * Walk the tree once, counting files per language globally and per workspace.\n * A workspace is any directory passed in `workspaceRels` (relative, POSIX-normalised).\n * Root workspace is represented as \"\" and always included.\n *\n * The walker skips IGNORED_DIRS (node_modules, target, dist, etc.) — a file inside\n * node_modules is never counted.\n */\nexport async function detectLanguages(\n projectRoot: string,\n workspaceRels: string[],\n): Promise<ProjectLanguage[]> {\n const globalCounts = new Map<string, number>();\n const perWorkspace = new Map<string, Map<string, number>>(); // workspace_rel → lang → count\n\n // Sort workspace rels longest-first so deeper workspaces claim their files before parents.\n const sortedRels = [...workspaceRels, '']\n .filter((v, i, arr) => arr.indexOf(v) === i)\n .sort((a, b) => b.length - a.length);\n for (const rel of sortedRels) perWorkspace.set(rel, new Map());\n\n await walk(projectRoot, projectRoot, globalCounts, perWorkspace, sortedRels);\n\n return [...globalCounts.entries()]\n .map(([name, file_count]) => {\n const workspaces = sortedRels\n .filter((rel) => (perWorkspace.get(rel)?.get(name) ?? 0) > 0)\n .map((rel) => rel || '.');\n return { name, file_count, workspaces };\n })\n .filter((l) => l.file_count > 0)\n .sort((a, b) => b.file_count - a.file_count);\n}\n\nasync function walk(\n root: string,\n dir: string,\n global: Map<string, number>,\n perWorkspace: Map<string, Map<string, number>>,\n workspaceRels: string[],\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.github') {\n if (!['.toolcairn', '.claude'].includes(entry.name)) continue;\n }\n if (IGNORED_DIRS.has(entry.name)) continue;\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(root, full, global, perWorkspace, workspaceRels);\n } else if (entry.isFile()) {\n const ext = pickExtension(entry.name);\n if (!ext) continue;\n const lang = EXT_TO_LANGUAGE[ext];\n if (!lang) continue;\n global.set(lang, (global.get(lang) ?? 0) + 1);\n // Find the deepest workspace that owns this file\n const relFile = relative(root, full).split(sep).join('/');\n for (const wsRel of workspaceRels) {\n if (wsRel === '' || relFile === wsRel || relFile.startsWith(`${wsRel}/`)) {\n const m = perWorkspace.get(wsRel);\n if (m) m.set(lang, (m.get(lang) ?? 0) + 1);\n break;\n }\n }\n }\n }\n}\n\nfunction pickExtension(filename: string): string | null {\n const idx = filename.lastIndexOf('.');\n if (idx < 0 || idx === 0) return null;\n return filename.slice(idx).toLowerCase();\n}\n","import type { Ecosystem } from '@toolcairn/types';\nimport type { Parser } from '../types.js';\nimport { parseCargo } from './cargo.js';\nimport { parseComposer } from './composer.js';\nimport { parseDart } from './dart.js';\nimport { parseDotnet } from './dotnet.js';\nimport { parseGo } from './go.js';\nimport { parseGradle } from './gradle.js';\nimport { parseMaven } from './maven.js';\nimport { parseMix } from './mix.js';\nimport { parseNpm } from './npm.js';\nimport { parsePypi } from './pypi.js';\nimport { parseRuby } from './ruby.js';\nimport { parseSwift } from './swift.js';\n\nexport const PARSERS: Record<Ecosystem, Parser> = {\n npm: parseNpm,\n pypi: parsePypi,\n cargo: parseCargo,\n go: parseGo,\n rubygems: parseRuby,\n maven: parseMaven,\n gradle: parseGradle,\n composer: parseComposer,\n hex: parseMix,\n pub: parseDart,\n nuget: parseDotnet,\n 'swift-pm': parseSwift,\n};\n\nexport {\n parseCargo,\n parseComposer,\n parseDart,\n parseDotnet,\n parseGo,\n parseGradle,\n parseMaven,\n parseMix,\n parseNpm,\n parsePypi,\n parseRuby,\n parseSwift,\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseToml } from 'smol-toml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface CargoToml {\n package?: { name?: string };\n dependencies?: Record<string, string | { version?: string }>;\n 'dev-dependencies'?: Record<string, string | { version?: string }>;\n 'build-dependencies'?: Record<string, string | { version?: string }>;\n workspace?: {\n dependencies?: Record<string, string | { version?: string }>;\n members?: string[];\n };\n}\n\ninterface CargoLock {\n package?: Array<{ name?: string; version?: string }>;\n}\n\nconst SECTION_MAP: Array<[keyof CargoToml, ManifestSection]> = [\n ['dependencies', 'dep'],\n ['dev-dependencies', 'dev'],\n ['build-dependencies', 'build'],\n];\n\nfunction extractDeps(\n obj: Record<string, string | { version?: string }> | undefined,\n section: ManifestSection,\n resolved: Map<string, string>,\n out: ParseResult['tools'],\n manifestFile: string,\n workspaceRel: string,\n): void {\n if (!obj) return;\n for (const [name, value] of Object.entries(obj)) {\n const constraint = typeof value === 'string' ? value : value.version;\n out.push({\n name,\n ecosystem: 'cargo',\n version_constraint: constraint,\n resolved_version: resolved.get(name),\n section,\n manifest_file: manifestFile,\n workspace_path: workspaceRel,\n });\n }\n}\n\nexport const parseCargo: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const manifestPath = join(workspace_dir, 'Cargo.toml');\n if (!(await fileExists(manifestPath))) return { ecosystem: 'cargo', tools, warnings };\n\n let manifest: CargoToml;\n try {\n manifest = parseToml(await readFile(manifestPath, 'utf-8')) as CargoToml;\n } catch (err) {\n warnings.push({\n scope: 'parser:cargo',\n path: manifestPath,\n message: `Failed to parse Cargo.toml: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'cargo', tools, warnings };\n }\n\n const resolved = new Map<string, string>();\n const lockPath = join(workspace_dir, 'Cargo.lock');\n if (await fileExists(lockPath)) {\n try {\n const lock = parseToml(await readFile(lockPath, 'utf-8')) as CargoLock;\n for (const pkg of lock.package ?? []) {\n if (pkg.name && pkg.version) resolved.set(pkg.name, pkg.version);\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:cargo',\n path: lockPath,\n message: `Failed to parse Cargo.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/Cargo.toml` : 'Cargo.toml';\n\n for (const [field, section] of SECTION_MAP) {\n extractDeps(\n manifest[field] as Record<string, string | { version?: string }> | undefined,\n section,\n resolved,\n tools,\n manifestFile,\n workspace_rel,\n );\n }\n\n // Workspace-level dependencies (shared across members)\n extractDeps(\n manifest.workspace?.dependencies,\n 'dep',\n resolved,\n tools,\n manifestFile,\n workspace_rel,\n );\n\n return { ecosystem: 'cargo', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface ComposerJson {\n require?: Record<string, string>;\n 'require-dev'?: Record<string, string>;\n}\n\ninterface ComposerLockPackage {\n name?: string;\n version?: string;\n}\n\ninterface ComposerLock {\n packages?: ComposerLockPackage[];\n 'packages-dev'?: ComposerLockPackage[];\n}\n\n/** Skips PHP platform pseudo-packages that aren't real deps. */\nfunction isPhpPlatform(name: string): boolean {\n return name === 'php' || name.startsWith('ext-') || name.startsWith('lib-');\n}\n\nexport const parseComposer: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'composer.lock');\n const manifestPath = join(workspace_dir, 'composer.json');\n\n // Prefer lockfile\n if (await fileExists(lockPath)) {\n try {\n const lock = JSON.parse(await readFile(lockPath, 'utf-8')) as ComposerLock;\n const manifestFile = workspace_rel ? `${workspace_rel}/composer.lock` : 'composer.lock';\n for (const [pkgs, section] of [\n [lock.packages ?? [], 'dep'] as const,\n [lock['packages-dev'] ?? [], 'dev'] as const,\n ]) {\n for (const pkg of pkgs) {\n if (!pkg.name || isPhpPlatform(pkg.name)) continue;\n tools.push({\n name: pkg.name,\n ecosystem: 'composer',\n version_constraint: undefined,\n resolved_version: pkg.version,\n section: section as ManifestSection,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n if (tools.length > 0) return { ecosystem: 'composer', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:composer',\n path: lockPath,\n message: `Failed to parse composer.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: composer.json\n if (await fileExists(manifestPath)) {\n try {\n const manifest = JSON.parse(await readFile(manifestPath, 'utf-8')) as ComposerJson;\n const manifestFile = workspace_rel ? `${workspace_rel}/composer.json` : 'composer.json';\n for (const [obj, section] of [\n [manifest.require, 'dep'] as const,\n [manifest['require-dev'], 'dev'] as const,\n ]) {\n for (const [name, constraint] of Object.entries(obj ?? {})) {\n if (isPhpPlatform(name)) continue;\n tools.push({\n name,\n ecosystem: 'composer',\n version_constraint: constraint,\n section: section as ManifestSection,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:composer',\n path: manifestPath,\n message: `Failed to parse composer.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'composer', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseYaml } from 'yaml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface Pubspec {\n name?: string;\n dependencies?: Record<string, string | { version?: string; sdk?: string; path?: string }>;\n dev_dependencies?: Record<string, string | { version?: string; sdk?: string; path?: string }>;\n}\n\ninterface PubspecLockPackage {\n version?: string;\n dependency?: string;\n}\n\ninterface PubspecLock {\n packages?: Record<string, PubspecLockPackage>;\n}\n\nfunction isSkippableDep(value: unknown): boolean {\n if (typeof value === 'object' && value !== null) {\n const v = value as { sdk?: string; path?: string };\n if (v.sdk || v.path) return true;\n }\n return false;\n}\n\nfunction extractDeps(\n obj: Pubspec['dependencies'],\n section: ManifestSection,\n resolved: Map<string, string>,\n out: ParseResult['tools'],\n manifestFile: string,\n workspaceRel: string,\n): void {\n if (!obj) return;\n for (const [name, value] of Object.entries(obj)) {\n if (isSkippableDep(value)) continue;\n const constraint = typeof value === 'string' ? value : value.version;\n out.push({\n name,\n ecosystem: 'pub',\n version_constraint: constraint,\n resolved_version: resolved.get(name),\n section,\n manifest_file: manifestFile,\n workspace_path: workspaceRel,\n });\n }\n}\n\nexport const parseDart: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const pubspecPath = join(workspace_dir, 'pubspec.yaml');\n if (!(await fileExists(pubspecPath))) return { ecosystem: 'pub', tools, warnings };\n\n let pubspec: Pubspec;\n try {\n pubspec = parseYaml(await readFile(pubspecPath, 'utf-8')) as Pubspec;\n } catch (err) {\n warnings.push({\n scope: 'parser:dart',\n path: pubspecPath,\n message: `Failed to parse pubspec.yaml: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'pub', tools, warnings };\n }\n\n const resolved = new Map<string, string>();\n const lockPath = join(workspace_dir, 'pubspec.lock');\n if (await fileExists(lockPath)) {\n try {\n const lock = parseYaml(await readFile(lockPath, 'utf-8')) as PubspecLock;\n for (const [name, pkg] of Object.entries(lock.packages ?? {})) {\n if (pkg.version) resolved.set(name, pkg.version);\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:dart',\n path: lockPath,\n message: `Failed to parse pubspec.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/pubspec.yaml` : 'pubspec.yaml';\n extractDeps(pubspec.dependencies, 'dep', resolved, tools, manifestFile, workspace_rel);\n extractDeps(pubspec.dev_dependencies, 'dev', resolved, tools, manifestFile, workspace_rel);\n\n return { ecosystem: 'pub', tools, warnings };\n};\n","import { readFile, readdir } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport { XMLParser } from 'fast-xml-parser';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PackageRef {\n '@_Include'?: string;\n '@_Version'?: string;\n '@_PrivateAssets'?: string;\n}\n\ninterface CsProj {\n Project?: {\n ItemGroup?:\n | { PackageReference?: PackageRef | PackageRef[] }\n | Array<{ PackageReference?: PackageRef | PackageRef[] }>;\n };\n}\n\ninterface PackagesConfig {\n packages?: {\n package?: PackageRef | PackageRef[];\n };\n}\n\nfunction toArray<T>(v: T | T[] | undefined): T[] {\n if (v === undefined) return [];\n return Array.isArray(v) ? v : [v];\n}\n\nexport const parseDotnet: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n let entries: string[] = [];\n try {\n entries = await readdir(workspace_dir);\n } catch {\n return { ecosystem: 'nuget', tools, warnings };\n }\n\n const csprojFiles = entries.filter((f) => f.endsWith('.csproj') || f.endsWith('.fsproj'));\n const xmlParser = new XMLParser({ ignoreAttributes: false });\n\n for (const proj of csprojFiles) {\n const path = join(workspace_dir, proj);\n try {\n const raw = await readFile(path, 'utf-8');\n const doc = xmlParser.parse(raw) as CsProj;\n const itemGroups = Array.isArray(doc.Project?.ItemGroup)\n ? (doc.Project?.ItemGroup ?? [])\n : doc.Project?.ItemGroup\n ? [doc.Project.ItemGroup]\n : [];\n const manifestFile = workspace_rel\n ? `${workspace_rel}/${relative(workspace_dir, path)}`\n : relative(workspace_dir, path);\n for (const group of itemGroups) {\n for (const ref of toArray(group.PackageReference)) {\n const name = ref['@_Include'];\n if (!name) continue;\n const version = ref['@_Version'];\n tools.push({\n name,\n ecosystem: 'nuget',\n version_constraint: version,\n resolved_version: version,\n section: ref['@_PrivateAssets'] ? 'build' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:dotnet',\n path,\n message: `Failed to parse ${proj}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Legacy packages.config (full framework)\n const pkgConfigPath = join(workspace_dir, 'packages.config');\n if (await fileExists(pkgConfigPath)) {\n try {\n const raw = await readFile(pkgConfigPath, 'utf-8');\n const doc = xmlParser.parse(raw) as PackagesConfig;\n const manifestFile = workspace_rel ? `${workspace_rel}/packages.config` : 'packages.config';\n for (const pkg of toArray(doc.packages?.package)) {\n const name = pkg['@_Include'];\n if (!name) continue;\n tools.push({\n name,\n ecosystem: 'nuget',\n version_constraint: pkg['@_Version'],\n resolved_version: pkg['@_Version'],\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:dotnet',\n path: pkgConfigPath,\n message: `Failed to parse packages.config: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'nuget', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/**\n * Parses go.mod — line-oriented format:\n * require (\n * github.com/foo/bar v1.2.3\n * github.com/baz/qux v0.5.1 // indirect\n * )\n * Or single-line: require github.com/foo/bar v1.2.3\n */\nfunction parseGoMod(raw: string): Array<{ name: string; version: string; indirect: boolean }> {\n const out: Array<{ name: string; version: string; indirect: boolean }> = [];\n const lines = raw.split('\\n');\n let inRequireBlock = false;\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\/\\/.*$/, '').trim();\n const commentTail = rawLine.match(/\\/\\/\\s*(.*)$/)?.[1] ?? '';\n const indirect = /\\bindirect\\b/.test(commentTail);\n if (!line) continue;\n if (line === 'require (') {\n inRequireBlock = true;\n continue;\n }\n if (line === ')') {\n inRequireBlock = false;\n continue;\n }\n if (line.startsWith('require ')) {\n // single-line require github.com/x v1.0.0\n const parts = line.slice(8).trim().split(/\\s+/);\n if (parts[0] && parts[1]) out.push({ name: parts[0], version: parts[1], indirect });\n continue;\n }\n if (inRequireBlock) {\n const parts = line.split(/\\s+/);\n if (parts[0] && parts[1]) out.push({ name: parts[0], version: parts[1], indirect });\n }\n }\n return out;\n}\n\nexport const parseGo: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const modPath = join(workspace_dir, 'go.mod');\n if (!(await fileExists(modPath))) return { ecosystem: 'go', tools, warnings };\n\n try {\n const raw = await readFile(modPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/go.mod` : 'go.mod';\n for (const dep of parseGoMod(raw)) {\n tools.push({\n name: dep.name,\n ecosystem: 'go',\n version_constraint: dep.version,\n resolved_version: dep.version, // go.mod pins exact version\n section: dep.indirect ? 'optional' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:go',\n path: modPath,\n message: `Failed to parse go.mod: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n return { ecosystem: 'go', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/** gradle.lockfile is deterministic: one line per dep as \"group:name:version=configurations\". */\nfunction parseGradleLockfile(\n raw: string,\n): Array<{ group: string; name: string; version: string; configurations: string[] }> {\n const out: Array<{ group: string; name: string; version: string; configurations: string[] }> = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const match = trimmed.match(/^([^:]+):([^:]+):([^=]+)=(.*)$/);\n if (match?.[1] && match[2] && match[3]) {\n out.push({\n group: match[1],\n name: match[2],\n version: match[3],\n configurations: (match[4] ?? '').split(',').map((s) => s.trim()),\n });\n }\n }\n return out;\n}\n\nfunction gradleConfigToSection(configs: string[]): ManifestSection {\n const joined = configs.join(' ').toLowerCase();\n if (joined.includes('test')) return 'dev';\n if (joined.includes('annotationprocessor') || joined.includes('kapt')) return 'build';\n return 'dep';\n}\n\n/** Shallow build.gradle(.kts) regex scan: `implementation \"group:name:version\"`. */\nfunction parseBuildGradle(raw: string): Array<{ spec: string; config: string }> {\n const out: Array<{ spec: string; config: string }> = [];\n // Groovy: implementation 'group:name:version'\n // Kotlin: implementation(\"group:name:version\")\n const patterns = [\n /(implementation|api|compileOnly|runtimeOnly|testImplementation|testRuntimeOnly|annotationProcessor|kapt|ksp)\\s*\\(?\\s*(['\"])([A-Za-z0-9_.\\-]+:[A-Za-z0-9_.\\-]+:[^'\"]+)\\2/g,\n ];\n for (const pattern of patterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n if (match[1] && match[3]) out.push({ spec: match[3], config: match[1] });\n }\n }\n return out;\n}\n\nfunction configKeywordToSection(config: string): ManifestSection {\n const c = config.toLowerCase();\n if (c.startsWith('test')) return 'dev';\n if (c.includes('annotationprocessor') || c === 'kapt' || c === 'ksp') return 'build';\n return 'dep';\n}\n\nexport const parseGradle: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'gradle.lockfile');\n if (await fileExists(lockPath)) {\n try {\n const raw = await readFile(lockPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/gradle.lockfile` : 'gradle.lockfile';\n for (const dep of parseGradleLockfile(raw)) {\n tools.push({\n name: `${dep.group}:${dep.name}`,\n ecosystem: 'gradle',\n version_constraint: dep.version,\n resolved_version: dep.version,\n section: gradleConfigToSection(dep.configurations),\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'gradle', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:gradle',\n path: lockPath,\n message: `Failed to parse gradle.lockfile: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: shallow regex scan of build.gradle / build.gradle.kts\n for (const filename of ['build.gradle.kts', 'build.gradle']) {\n const path = join(workspace_dir, filename);\n if (!(await fileExists(path))) continue;\n try {\n const raw = await readFile(path, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/${filename}` : filename;\n let hasVariable = false;\n for (const dep of parseBuildGradle(raw)) {\n const parts = dep.spec.split(':');\n if (parts.length < 3 || !parts[0] || !parts[1]) continue;\n const version = parts.slice(2).join(':');\n if (version.startsWith('$') || version.includes('${')) {\n hasVariable = true;\n continue;\n }\n tools.push({\n name: `${parts[0]}:${parts[1]}`,\n ecosystem: 'gradle',\n version_constraint: version,\n section: configKeywordToSection(dep.config),\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n warnings.push({\n scope: 'parser:gradle',\n path: manifestFile,\n message:\n 'Shallow parse of build.gradle — results may be incomplete. Add `dependencyLocking` to the project for deterministic discovery.',\n });\n if (hasVariable) {\n warnings.push({\n scope: 'parser:gradle',\n path: manifestFile,\n message: 'Some deps use variable interpolation ($ver / ${var}) — skipped.',\n });\n }\n break;\n } catch (err) {\n warnings.push({\n scope: 'parser:gradle',\n path,\n message: `Failed to read ${filename}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'gradle', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { XMLParser } from 'fast-xml-parser';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface MavenDep {\n groupId?: string;\n artifactId?: string;\n version?: string;\n scope?: string;\n optional?: string | boolean;\n}\n\ninterface MavenPom {\n project?: {\n dependencies?: { dependency?: MavenDep | MavenDep[] };\n dependencyManagement?: { dependencies?: { dependency?: MavenDep | MavenDep[] } };\n };\n}\n\nfunction scopeToSection(scope: string | undefined, optional: boolean): ManifestSection {\n if (optional) return 'optional';\n switch (scope) {\n case 'test':\n case 'provided':\n return 'dev';\n default:\n return 'dep';\n }\n}\n\nfunction toArray<T>(v: T | T[] | undefined): T[] {\n if (v === undefined) return [];\n return Array.isArray(v) ? v : [v];\n}\n\nexport const parseMaven: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const pomPath = join(workspace_dir, 'pom.xml');\n if (!(await fileExists(pomPath))) return { ecosystem: 'maven', tools, warnings };\n\n let doc: MavenPom;\n try {\n const raw = await readFile(pomPath, 'utf-8');\n const parser = new XMLParser({ ignoreAttributes: true, parseTagValue: true });\n doc = parser.parse(raw) as MavenPom;\n } catch (err) {\n warnings.push({\n scope: 'parser:maven',\n path: pomPath,\n message: `Failed to parse pom.xml: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'maven', tools, warnings };\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/pom.xml` : 'pom.xml';\n const deps = toArray(doc.project?.dependencies?.dependency);\n const managedDeps = toArray(doc.project?.dependencyManagement?.dependencies?.dependency);\n let hasUnresolvedVariable = false;\n\n for (const dep of [...deps, ...managedDeps]) {\n if (!dep.groupId || !dep.artifactId) continue;\n const name = `${dep.groupId}:${dep.artifactId}`;\n const version = typeof dep.version === 'string' ? dep.version : undefined;\n if (version && version.includes('${')) hasUnresolvedVariable = true;\n const optional = dep.optional === true || dep.optional === 'true';\n tools.push({\n name,\n ecosystem: 'maven',\n version_constraint: version,\n resolved_version: version && !version.includes('${') ? version : undefined,\n section: scopeToSection(dep.scope, optional),\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n\n if (hasUnresolvedVariable) {\n warnings.push({\n scope: 'parser:maven',\n path: pomPath,\n message:\n 'Some dependencies use ${...} variable interpolation which is not resolved — version info may be incomplete.',\n });\n }\n\n return { ecosystem: 'maven', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/**\n * mix.lock format (Elixir):\n * %{\n * \"phoenix\": {:hex, :phoenix, \"1.7.10\", \"hash\", [...], [...]},\n * \"ecto\": {:hex, :ecto, \"3.11.0\", \"hash\", [...]}\n * }\n *\n * We just need name + version — extract via regex.\n */\nfunction parseMixLock(raw: string): Array<{ name: string; version: string }> {\n const out: Array<{ name: string; version: string }> = [];\n const pattern = /\"([^\"]+)\":\\s*\\{\\s*:hex\\s*,\\s*:[A-Za-z_][A-Za-z0-9_]*\\s*,\\s*\"([^\"]+)\"/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n if (match[1] && match[2]) out.push({ name: match[1], version: match[2] });\n }\n return out;\n}\n\n/**\n * mix.exs deps/0 block (fallback if no mix.lock):\n * defp deps do\n * [\n * {:phoenix, \"~> 1.7\"},\n * {:ecto, \"~> 3.11\", only: [:dev]}\n * ]\n * end\n */\nfunction parseMixExs(raw: string): Array<{ name: string; constraint?: string; dev: boolean }> {\n const out: Array<{ name: string; constraint?: string; dev: boolean }> = [];\n const pattern =\n /\\{:([a-z_][a-z0-9_]*)\\s*,\\s*\"([^\"]+)\"(?:[^}]*only:\\s*(?:\\[?:?([a-z_]+))?[^}]*)?\\}/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n if (match[1]) {\n const onlyScope = match[3];\n out.push({\n name: match[1],\n constraint: match[2],\n dev: onlyScope === 'dev' || onlyScope === 'test',\n });\n }\n }\n return out;\n}\n\nexport const parseMix: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'mix.lock');\n if (await fileExists(lockPath)) {\n try {\n const raw = await readFile(lockPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/mix.lock` : 'mix.lock';\n for (const dep of parseMixLock(raw)) {\n tools.push({\n name: dep.name,\n ecosystem: 'hex',\n version_constraint: undefined,\n resolved_version: dep.version,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'hex', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:mix',\n path: lockPath,\n message: `Failed to parse mix.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n const exsPath = join(workspace_dir, 'mix.exs');\n if (await fileExists(exsPath)) {\n try {\n const raw = await readFile(exsPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/mix.exs` : 'mix.exs';\n for (const dep of parseMixExs(raw)) {\n tools.push({\n name: dep.name,\n ecosystem: 'hex',\n version_constraint: dep.constraint,\n section: dep.dev ? 'dev' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:mix',\n path: exsPath,\n message: `Failed to parse mix.exs: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'hex', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseYaml } from 'yaml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n workspaces?: string[] | { packages?: string[] };\n}\n\ninterface PnpmLockPackage {\n version?: string;\n}\n\ninterface PnpmLock {\n importers?: Record<\n string,\n {\n dependencies?: Record<string, { version?: string } | string>;\n devDependencies?: Record<string, { version?: string } | string>;\n peerDependencies?: Record<string, { version?: string } | string>;\n optionalDependencies?: Record<string, { version?: string } | string>;\n }\n >;\n packages?: Record<string, PnpmLockPackage>;\n}\n\ninterface NpmLockDep {\n version?: string;\n resolved?: string;\n dev?: boolean;\n optional?: boolean;\n peer?: boolean;\n}\n\ninterface NpmLock {\n packages?: Record<string, NpmLockDep>;\n dependencies?: Record<string, NpmLockDep>;\n}\n\nconst SECTION_MAP: Array<[keyof PackageJson, ManifestSection]> = [\n ['dependencies', 'dep'],\n ['devDependencies', 'dev'],\n ['peerDependencies', 'peer'],\n ['optionalDependencies', 'optional'],\n];\n\n/** Extracts raw `X.Y.Z` version from a pnpm key like \"/@scope/name@1.2.3(peer@...)\". */\nfunction stripPnpmRange(raw: string): string | undefined {\n // pnpm v6/v7 entries in `packages` look like \"/react@18.2.0(peer@...)\".\n const atIdx = raw.lastIndexOf('@');\n if (atIdx <= 0) return undefined;\n const tail = raw.slice(atIdx + 1);\n const parenIdx = tail.indexOf('(');\n return parenIdx >= 0 ? tail.slice(0, parenIdx) : tail || undefined;\n}\n\n/** Resolves a dep's version from pnpm-lock importers + packages. */\nfunction resolvePnpmVersion(\n lock: PnpmLock,\n importerKey: string,\n section: 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies',\n depName: string,\n): string | undefined {\n const importer = lock.importers?.[importerKey];\n const entry = importer?.[section]?.[depName];\n if (!entry) return undefined;\n if (typeof entry === 'string') return entry;\n if (entry.version) {\n // pnpm v8+: version field contains the raw version; strip any \"(peer...)\" suffix\n const parenIdx = entry.version.indexOf('(');\n return parenIdx >= 0 ? entry.version.slice(0, parenIdx) : entry.version;\n }\n return undefined;\n}\n\n/** Resolves from package-lock.json (npm v7+ `packages` object keyed by \"node_modules/X\"). */\nfunction resolveNpmLockVersion(lock: NpmLock, depName: string): string | undefined {\n const key = `node_modules/${depName}`;\n return lock.packages?.[key]?.version ?? lock.dependencies?.[depName]?.version;\n}\n\nexport const parseNpm: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const manifestPath = join(workspace_dir, 'package.json');\n if (!(await fileExists(manifestPath))) {\n return { ecosystem: 'npm', tools, warnings };\n }\n\n let manifest: PackageJson;\n try {\n manifest = JSON.parse(await readFile(manifestPath, 'utf-8')) as PackageJson;\n } catch (err) {\n warnings.push({\n scope: 'parser:npm',\n path: manifestPath,\n message: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'npm', tools, warnings };\n }\n\n // Try to load a lockfile for resolved versions. Prefer pnpm > npm > yarn.\n let pnpmLock: PnpmLock | undefined;\n let npmLock: NpmLock | undefined;\n\n const pnpmLockPath = join(workspace_dir, 'pnpm-lock.yaml');\n const npmLockPath = join(workspace_dir, 'package-lock.json');\n\n if (await fileExists(pnpmLockPath)) {\n try {\n pnpmLock = parseYaml(await readFile(pnpmLockPath, 'utf-8')) as PnpmLock;\n } catch (err) {\n warnings.push({\n scope: 'parser:npm',\n path: pnpmLockPath,\n message: `Failed to parse pnpm-lock.yaml, falling back to manifest: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n } else if (await fileExists(npmLockPath)) {\n try {\n npmLock = JSON.parse(await readFile(npmLockPath, 'utf-8')) as NpmLock;\n } catch (err) {\n warnings.push({\n scope: 'parser:npm',\n path: npmLockPath,\n message: `Failed to parse package-lock.json, falling back to manifest: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n } else if (!(await fileExists(join(workspace_dir, 'yarn.lock')))) {\n warnings.push({\n scope: 'parser:npm',\n path: manifestPath,\n message: 'No lockfile present — resolved_version will be absent.',\n });\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/package.json` : 'package.json';\n // In pnpm-lock, the root importer is \".\" and sub-workspaces use their relative paths.\n const pnpmImporterKey = workspace_rel || '.';\n\n for (const [field, section] of SECTION_MAP) {\n const deps = manifest[field] as Record<string, string> | undefined;\n if (!deps) continue;\n for (const [name, constraint] of Object.entries(deps)) {\n let resolved: string | undefined;\n if (pnpmLock) {\n resolved = resolvePnpmVersion(\n pnpmLock,\n pnpmImporterKey,\n field as Exclude<typeof field, 'workspaces' | 'name'>,\n name,\n );\n } else if (npmLock) {\n resolved = resolveNpmLockVersion(npmLock, name);\n }\n\n tools.push({\n name,\n ecosystem: 'npm',\n version_constraint: constraint,\n resolved_version: resolved,\n section,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n\n // Avoid unused-symbol warnings — stripPnpmRange is reserved for future \"packages\" fallback.\n void stripPnpmRange;\n\n return { ecosystem: 'npm', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseToml } from 'smol-toml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PyProject {\n project?: {\n name?: string;\n dependencies?: string[];\n 'optional-dependencies'?: Record<string, string[]>;\n };\n tool?: {\n poetry?: {\n name?: string;\n dependencies?: Record<string, string | { version?: string }>;\n 'dev-dependencies'?: Record<string, string | { version?: string }>;\n group?: Record<string, { dependencies?: Record<string, string | { version?: string }> }>;\n };\n uv?: {\n 'dev-dependencies'?: string[];\n };\n };\n 'dependency-groups'?: Record<string, string[]>;\n}\n\ninterface UvLockPackage {\n name?: string;\n version?: string;\n}\n\ninterface UvLock {\n package?: UvLockPackage[];\n}\n\n/** Parses \"fastapi>=0.100.0\" / \"django[argon2]<5\" into {name, constraint}. */\nfunction parseRequirementString(raw: string): { name: string; constraint?: string } | null {\n const trimmed = raw.trim();\n if (!trimmed || trimmed.startsWith('#')) return null;\n // Split on first of <, >, =, ~, !, [, ;, space\n const match = trimmed.match(/^([A-Za-z0-9_.\\-]+)(\\[[^\\]]*\\])?(.*)$/);\n if (!match || !match[1]) return null;\n const constraint = (match[3] ?? '').trim();\n return { name: match[1], constraint: constraint || undefined };\n}\n\nfunction addPoetryDeps(\n obj: Record<string, string | { version?: string }> | undefined,\n section: ManifestSection,\n out: ParseResult['tools'],\n manifestFile: string,\n workspaceRel: string,\n resolvedVersions: Map<string, string>,\n): void {\n if (!obj) return;\n for (const [name, value] of Object.entries(obj)) {\n if (name === 'python') continue; // Poetry's python interpreter pin\n const constraint = typeof value === 'string' ? value : value.version;\n out.push({\n name,\n ecosystem: 'pypi',\n version_constraint: constraint,\n resolved_version: resolvedVersions.get(name.toLowerCase()),\n section,\n manifest_file: manifestFile,\n workspace_path: workspaceRel,\n });\n }\n}\n\nexport const parsePypi: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n // Build resolved-version map from uv.lock if present.\n const resolved = new Map<string, string>();\n const uvLockPath = join(workspace_dir, 'uv.lock');\n if (await fileExists(uvLockPath)) {\n try {\n const lock = parseToml(await readFile(uvLockPath, 'utf-8')) as UvLock;\n for (const pkg of lock.package ?? []) {\n if (pkg.name && pkg.version) resolved.set(pkg.name.toLowerCase(), pkg.version);\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:pypi',\n path: uvLockPath,\n message: `Failed to parse uv.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // 1) pyproject.toml (strongest signal)\n const pyprojectPath = join(workspace_dir, 'pyproject.toml');\n if (await fileExists(pyprojectPath)) {\n try {\n const doc = parseToml(await readFile(pyprojectPath, 'utf-8')) as PyProject;\n const manifestFile = workspace_rel ? `${workspace_rel}/pyproject.toml` : 'pyproject.toml';\n\n // PEP 621 / uv style: [project].dependencies = [\"fastapi>=0.100\", ...]\n for (const dep of doc.project?.dependencies ?? []) {\n const parsed = parseRequirementString(dep);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n for (const [groupName, deps] of Object.entries(\n doc.project?.['optional-dependencies'] ?? {},\n )) {\n for (const dep of deps) {\n const parsed = parseRequirementString(dep);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section: groupName === 'dev' ? 'dev' : 'optional',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n\n // PEP 735 / uv style: [dependency-groups]\n for (const [groupName, deps] of Object.entries(doc['dependency-groups'] ?? {})) {\n for (const dep of deps) {\n const parsed = parseRequirementString(dep);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section: groupName === 'dev' ? 'dev' : 'optional',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n\n // Poetry style: [tool.poetry.dependencies]\n addPoetryDeps(\n doc.tool?.poetry?.dependencies,\n 'dep',\n tools,\n manifestFile,\n workspace_rel,\n resolved,\n );\n addPoetryDeps(\n doc.tool?.poetry?.['dev-dependencies'],\n 'dev',\n tools,\n manifestFile,\n workspace_rel,\n resolved,\n );\n for (const group of Object.values(doc.tool?.poetry?.group ?? {})) {\n addPoetryDeps(group.dependencies, 'dev', tools, manifestFile, workspace_rel, resolved);\n }\n\n if (tools.length > 0) return { ecosystem: 'pypi', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:pypi',\n path: pyprojectPath,\n message: `Failed to parse pyproject.toml: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // 2) Fallback: requirements.txt (+ requirements-dev.txt)\n for (const [file, section] of [\n ['requirements.txt', 'dep'] as const,\n ['requirements-dev.txt', 'dev'] as const,\n ['dev-requirements.txt', 'dev'] as const,\n ]) {\n const path = join(workspace_dir, file);\n if (!(await fileExists(path))) continue;\n try {\n const raw = await readFile(path, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/${file}` : file;\n for (const line of raw.split('\\n')) {\n const parsed = parseRequirementString(line);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:pypi',\n path,\n message: `Failed to read ${file}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'pypi', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/**\n * Parses Gemfile.lock GEM section:\n * GEM\n * remote: https://rubygems.org/\n * specs:\n * rails (7.1.2)\n * actionmailer (7.1.2)\n */\nfunction parseGemfileLock(raw: string): Array<{ name: string; version: string }> {\n const out: Array<{ name: string; version: string }> = [];\n const lines = raw.split('\\n');\n let inSpecs = false;\n for (const line of lines) {\n if (line.trim() === 'specs:') {\n inSpecs = true;\n continue;\n }\n if (inSpecs) {\n if (!line.startsWith(' ')) {\n inSpecs = false;\n continue;\n }\n // 4-space indented = top-level spec; 6-space indented = transitive dep\n const match = line.match(/^ {4}([A-Za-z0-9_\\-.]+) \\(([^)]+)\\)/);\n if (match?.[1] && match[2]) out.push({ name: match[1], version: match[2] });\n }\n }\n return out;\n}\n\n/**\n * Parses Gemfile — Ruby DSL:\n * gem 'rails', '~> 7.1'\n * gem \"devise\"\n * group :development do\n * gem \"rspec-rails\"\n * end\n */\nfunction parseGemfile(raw: string): Array<{ name: string; constraint?: string; dev: boolean }> {\n const out: Array<{ name: string; constraint?: string; dev: boolean }> = [];\n const lines = raw.split('\\n');\n let groupDepth = 0;\n let inDevGroup = false;\n for (const rawLine of lines) {\n const line = rawLine.split('#')[0]?.trim() ?? '';\n if (!line) continue;\n const groupMatch = line.match(/^group\\s+(:[\\w,\\s:]+?)\\s*do\\s*$/);\n if (groupMatch && groupMatch[1]) {\n groupDepth++;\n inDevGroup = /\\b(development|test)\\b/.test(groupMatch[1]);\n continue;\n }\n if (line === 'end' && groupDepth > 0) {\n groupDepth--;\n if (groupDepth === 0) inDevGroup = false;\n continue;\n }\n const gemMatch = line.match(/^gem\\s+(['\"])([A-Za-z0-9_\\-.]+)\\1(?:\\s*,\\s*(['\"])([^'\"]+)\\3)?/);\n if (gemMatch?.[2]) {\n out.push({ name: gemMatch[2], constraint: gemMatch[4], dev: inDevGroup });\n }\n }\n return out;\n}\n\nexport const parseRuby: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'Gemfile.lock');\n const gemfilePath = join(workspace_dir, 'Gemfile');\n\n // Prefer lockfile\n if (await fileExists(lockPath)) {\n try {\n const raw = await readFile(lockPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Gemfile.lock` : 'Gemfile.lock';\n // To know dep vs transitive, we also need Gemfile. Just mark all as 'dep' for now.\n const declared = new Set<string>();\n if (await fileExists(gemfilePath)) {\n try {\n const gemRaw = await readFile(gemfilePath, 'utf-8');\n for (const gem of parseGemfile(gemRaw)) declared.add(gem.name);\n } catch {\n /* non-fatal */\n }\n }\n for (const spec of parseGemfileLock(raw)) {\n // Skip if gemspec doesn't declare and we have a Gemfile — transitive\n if (declared.size > 0 && !declared.has(spec.name)) continue;\n tools.push({\n name: spec.name,\n ecosystem: 'rubygems',\n version_constraint: undefined,\n resolved_version: spec.version,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'rubygems', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:ruby',\n path: lockPath,\n message: `Failed to parse Gemfile.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: Gemfile\n if (await fileExists(gemfilePath)) {\n try {\n const raw = await readFile(gemfilePath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Gemfile` : 'Gemfile';\n for (const gem of parseGemfile(raw)) {\n tools.push({\n name: gem.name,\n ecosystem: 'rubygems',\n version_constraint: gem.constraint,\n section: gem.dev ? 'dev' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n warnings.push({\n scope: 'parser:ruby',\n path: manifestFile,\n message: 'No Gemfile.lock — resolved_version unavailable.',\n });\n } catch (err) {\n warnings.push({\n scope: 'parser:ruby',\n path: gemfilePath,\n message: `Failed to parse Gemfile: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'rubygems', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PackageResolvedV1 {\n object?: {\n pins?: Array<{\n package?: string;\n state?: { version?: string; branch?: string };\n }>;\n };\n pins?: Array<{\n identity?: string;\n location?: string;\n state?: { version?: string; branch?: string };\n }>;\n}\n\n/** Extracts package identity + version from Package.resolved (v1 or v2 format). */\nfunction parsePackageResolved(raw: string): Array<{ name: string; version?: string }> {\n let doc: PackageResolvedV1;\n try {\n doc = JSON.parse(raw) as PackageResolvedV1;\n } catch {\n return [];\n }\n const out: Array<{ name: string; version?: string }> = [];\n // v2 format\n for (const pin of doc.pins ?? []) {\n if (pin.identity) out.push({ name: pin.identity, version: pin.state?.version });\n }\n // v1 format\n for (const pin of doc.object?.pins ?? []) {\n if (pin.package) out.push({ name: pin.package, version: pin.state?.version });\n }\n return out;\n}\n\n/**\n * Swift Package.swift fallback (DSL):\n * .package(url: \"https://github.com/foo/bar.git\", from: \"1.0.0\")\n * .package(url: \"...\", .upToNextMajor(from: \"2.0.0\"))\n *\n * We extract the last segment of the URL as the identity and the raw version spec.\n */\nfunction parsePackageSwift(raw: string): Array<{ name: string; constraint?: string }> {\n const out: Array<{ name: string; constraint?: string }> = [];\n const pattern = /\\.package\\(\\s*(?:name:\\s*\"[^\"]+\"\\s*,\\s*)?url:\\s*\"([^\"]+)\"\\s*,\\s*([^)]+)\\)/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n const url = match[1];\n const spec = match[2]?.trim();\n if (!url) continue;\n // identity = last path segment, strip .git suffix\n const identity = url\n .split('/')\n .pop()\n ?.replace(/\\.git$/, '');\n if (!identity) continue;\n out.push({ name: identity, constraint: spec });\n }\n return out;\n}\n\nexport const parseSwift: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n // Prefer Package.resolved\n const resolvedPath = join(workspace_dir, 'Package.resolved');\n if (await fileExists(resolvedPath)) {\n try {\n const raw = await readFile(resolvedPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Package.resolved` : 'Package.resolved';\n for (const pkg of parsePackageResolved(raw)) {\n tools.push({\n name: pkg.name,\n ecosystem: 'swift-pm',\n resolved_version: pkg.version,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'swift-pm', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:swift',\n path: resolvedPath,\n message: `Failed to parse Package.resolved: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: Package.swift\n const swiftPath = join(workspace_dir, 'Package.swift');\n if (await fileExists(swiftPath)) {\n try {\n const raw = await readFile(swiftPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Package.swift` : 'Package.swift';\n for (const pkg of parsePackageSwift(raw)) {\n tools.push({\n name: pkg.name,\n ecosystem: 'swift-pm',\n version_constraint: pkg.constraint,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n warnings.push({\n scope: 'parser:swift',\n path: manifestFile,\n message: 'No Package.resolved — resolved_version unavailable.',\n });\n } catch (err) {\n warnings.push({\n scope: 'parser:swift',\n path: swiftPath,\n message: `Failed to parse Package.swift: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'swift-pm', tools, warnings };\n};\n","import { readdir } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport { IGNORED_DIRS, isDir } from '../util/fs.js';\n\n/**\n * Minimal glob-pattern expansion for workspace declarations.\n * Handles:\n * - exact paths: \"apps/web\"\n * - single-level wildcards: \"packages/*\"\n * - recursive wildcards: \"packages/**\" (treated same as packages/* + one level deep)\n * - negation: \"!packages/internal-*\" (excluded post-match)\n *\n * This is intentionally small — we don't need full minimatch semantics because\n * workspace globs are universally \"<prefix>/*\" or \"<prefix>/**\" in practice.\n */\nexport async function expandWorkspaceGlobs(rootDir: string, patterns: string[]): Promise<string[]> {\n const excluded = new Set<string>();\n const included = new Set<string>();\n\n for (const raw of patterns) {\n const pattern = raw.trim();\n if (!pattern) continue;\n const negated = pattern.startsWith('!');\n const clean = negated ? pattern.slice(1) : pattern;\n // Normalise separators to POSIX for pattern matching; join() later restores OS.\n const normalised = clean.replace(/\\\\/g, '/');\n const matches = await matchPattern(rootDir, normalised);\n const target = negated ? excluded : included;\n for (const m of matches) target.add(m);\n }\n\n return [...included].filter((p) => !excluded.has(p)).sort();\n}\n\nasync function matchPattern(rootDir: string, pattern: string): Promise<string[]> {\n const parts = pattern.split('/').filter(Boolean);\n const results: string[] = [];\n await walkPattern(rootDir, rootDir, parts, 0, results);\n return results;\n}\n\nasync function walkPattern(\n rootDir: string,\n currentDir: string,\n parts: string[],\n index: number,\n out: string[],\n): Promise<void> {\n if (index >= parts.length) {\n if (await isDir(currentDir)) out.push(currentDir);\n return;\n }\n const segment = parts[index];\n if (!segment) return;\n\n if (segment === '**') {\n // Match this level AND one level deep (common workspace pattern)\n await walkPattern(rootDir, currentDir, parts, index + 1, out);\n try {\n const entries = await readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) continue;\n await walkPattern(rootDir, join(currentDir, entry.name), parts, index, out);\n }\n } catch {\n /* skip */\n }\n return;\n }\n\n if (segment.includes('*')) {\n const re = globSegmentToRegex(segment);\n try {\n const entries = await readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) continue;\n if (re.test(entry.name)) {\n await walkPattern(rootDir, join(currentDir, entry.name), parts, index + 1, out);\n }\n }\n } catch {\n /* skip */\n }\n return;\n }\n\n // Literal segment\n await walkPattern(rootDir, join(currentDir, segment), parts, index + 1, out);\n}\n\nfunction globSegmentToRegex(segment: string): RegExp {\n const escaped = segment.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\n/** Convert absolute workspace dir to project-root-relative path with forward slashes. */\nexport function toRelPosix(projectRoot: string, absPath: string): string {\n const rel = relative(projectRoot, absPath);\n return rel.split(sep).join('/');\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport { parse as parseToml } from 'smol-toml';\nimport { parse as parseYaml } from 'yaml';\nimport { fileExists } from '../util/fs.js';\nimport { expandWorkspaceGlobs, toRelPosix } from './glob.js';\n\n/** Workspace declaration kinds we look for (in priority order per-dir). */\nconst WORKSPACE_FILES = [\n 'pnpm-workspace.yaml',\n 'package.json', // yarn / npm workspaces\n 'Cargo.toml', // [workspace] members\n 'go.work', // Go workspaces\n 'turbo.json', // often implies pnpm workspaces — don't add globs itself\n 'nx.json',\n 'lerna.json',\n] as const;\n\ninterface PackageJson {\n workspaces?: string[] | { packages?: string[] };\n}\n\ninterface PnpmWorkspace {\n packages?: string[];\n}\n\ninterface CargoWorkspaceToml {\n workspace?: { members?: string[] };\n}\n\ninterface LernaJson {\n packages?: string[];\n}\n\ninterface NxJson {\n workspaceLayout?: { projectsDir?: string };\n}\n\n/**\n * Discover all workspace roots inside a project.\n * Always includes the root itself. Then walks recursive workspace declarations up to `maxDepth`.\n * Returns absolute paths of every directory that should be scanned for manifests.\n */\nexport async function discoverWorkspaces(\n projectRoot: string,\n maxDepth = 5,\n): Promise<{ paths: string[]; warnings: DiscoveryWarning[] }> {\n const warnings: DiscoveryWarning[] = [];\n const discovered = new Set<string>([projectRoot]);\n const visited = new Set<string>();\n\n const queue: Array<{ dir: string; depth: number }> = [{ dir: projectRoot, depth: 0 }];\n\n while (queue.length > 0) {\n const { dir, depth } = queue.shift()!;\n if (visited.has(dir) || depth > maxDepth) continue;\n visited.add(dir);\n\n const globs = await readWorkspaceGlobs(dir, warnings);\n if (globs.length === 0) continue;\n\n const expanded = await expandWorkspaceGlobs(dir, globs);\n for (const sub of expanded) {\n if (!discovered.has(sub)) {\n discovered.add(sub);\n queue.push({ dir: sub, depth: depth + 1 });\n }\n }\n }\n\n return { paths: [...discovered].sort(), warnings };\n}\n\nasync function readWorkspaceGlobs(dir: string, warnings: DiscoveryWarning[]): Promise<string[]> {\n const globs: string[] = [];\n\n // pnpm-workspace.yaml\n const pnpmPath = join(dir, 'pnpm-workspace.yaml');\n if (await fileExists(pnpmPath)) {\n try {\n const doc = parseYaml(await readFile(pnpmPath, 'utf-8')) as PnpmWorkspace;\n if (Array.isArray(doc.packages)) globs.push(...doc.packages);\n } catch (err) {\n warnings.push({\n scope: 'workspace:pnpm',\n path: pnpmPath,\n message: `Failed to parse pnpm-workspace.yaml: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // package.json workspaces (npm / yarn)\n const pkgPath = join(dir, 'package.json');\n if (await fileExists(pkgPath)) {\n try {\n const doc = JSON.parse(await readFile(pkgPath, 'utf-8')) as PackageJson;\n if (Array.isArray(doc.workspaces)) {\n globs.push(...doc.workspaces);\n } else if (doc.workspaces && Array.isArray(doc.workspaces.packages)) {\n globs.push(...doc.workspaces.packages);\n }\n } catch (err) {\n warnings.push({\n scope: 'workspace:package-json',\n path: pkgPath,\n message: `Failed to parse package.json#workspaces: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Cargo.toml [workspace] members\n const cargoPath = join(dir, 'Cargo.toml');\n if (await fileExists(cargoPath)) {\n try {\n const doc = parseToml(await readFile(cargoPath, 'utf-8')) as CargoWorkspaceToml;\n if (Array.isArray(doc.workspace?.members)) globs.push(...doc.workspace.members);\n } catch (err) {\n warnings.push({\n scope: 'workspace:cargo',\n path: cargoPath,\n message: `Failed to parse Cargo workspace: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // go.work\n const goWorkPath = join(dir, 'go.work');\n if (await fileExists(goWorkPath)) {\n try {\n const raw = await readFile(goWorkPath, 'utf-8');\n const useMatch = raw.match(/use\\s*\\(([^)]*)\\)/s);\n if (useMatch?.[1]) {\n for (const line of useMatch[1].split('\\n')) {\n const trimmed = line.trim().replace(/^['\"]|['\"]$/g, '');\n if (trimmed && !trimmed.startsWith('//')) globs.push(trimmed);\n }\n } else {\n for (const line of raw.split('\\n')) {\n const m = line.match(/^\\s*use\\s+(.+)$/);\n if (m?.[1]) globs.push(m[1].trim().replace(/^['\"]|['\"]$/g, ''));\n }\n }\n } catch (err) {\n warnings.push({\n scope: 'workspace:go',\n path: goWorkPath,\n message: `Failed to parse go.work: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // lerna.json\n const lernaPath = join(dir, 'lerna.json');\n if (await fileExists(lernaPath)) {\n try {\n const doc = JSON.parse(await readFile(lernaPath, 'utf-8')) as LernaJson;\n if (Array.isArray(doc.packages)) globs.push(...doc.packages);\n } catch (err) {\n warnings.push({\n scope: 'workspace:lerna',\n path: lernaPath,\n message: `Failed to parse lerna.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // nx.json — defaults to \"packages/*\" when projectsDir unset\n const nxPath = join(dir, 'nx.json');\n if (await fileExists(nxPath)) {\n try {\n const doc = JSON.parse(await readFile(nxPath, 'utf-8')) as NxJson;\n const base = doc.workspaceLayout?.projectsDir ?? 'packages';\n globs.push(`${base}/*`);\n } catch (err) {\n warnings.push({\n scope: 'workspace:nx',\n path: nxPath,\n message: `Failed to parse nx.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return globs;\n}\n\n/**\n * Given a set of absolute workspace paths, produce `{path, manifest, ecosystem}`\n * entries for each workspace that has at least one manifest. Consumed by scanProject\n * to populate `project.subprojects`.\n */\nexport function summariseSubprojects(\n projectRoot: string,\n workspaces: string[],\n): Array<{ workspace_path: string; rel: string }> {\n return workspaces.map((abs) => ({ workspace_path: abs, rel: toRelPosix(projectRoot, abs) }));\n}\n","// Agent instruction templates for toolcairn_init.\n// Each function returns the section content to inject into the agent's instruction file.\n// The agent writes the content to the appropriate file — MCP server never touches the filesystem.\n\nexport type AgentType =\n | 'claude'\n | 'cursor'\n | 'windsurf'\n | 'copilot'\n | 'copilot-cli'\n | 'opencode'\n | 'generic';\n\ninterface InstructionTemplate {\n /** Target file path relative to project root */\n file_path: string;\n /** Whether to append to or create the file */\n mode: 'append' | 'create';\n /** Content to write/append */\n content: string;\n}\n\n// On Windows, npx is a .cmd shim — Claude Code + many MCP clients require a\n// `cmd /c` wrapper to spawn it. Detect the target host at server runtime.\nconst IS_WINDOWS = process.platform === 'win32';\n\nconst TOOLCAIRN_MCP_ENTRY = IS_WINDOWS\n ? {\n toolcairn: {\n command: 'cmd',\n args: ['/c', 'npx', '-y', '@neurynae/toolcairn-mcp'],\n },\n }\n : {\n toolcairn: {\n command: 'npx',\n args: ['-y', '@neurynae/toolcairn-mcp'],\n },\n };\n\nconst CORE_RULES = `\n## ToolCairn — Tool Intelligence MCP\n\nToolCairn is your tool intelligence co-pilot. It has a graph database of 500+ indexed tools with health signals, compatibility data, and known issue tracking. Always use it before recommending any tool, library, or framework.\n\n### The Server Owns .toolcairn/ (v0.10.0+)\n\nThe MCP server reads and writes \\`.toolcairn/config.json\\` and\n\\`.toolcairn/audit-log.jsonl\\` atomically under a cross-process lock.\nNEVER read or write these files directly — call the MCP tools instead.\n\n### Workflow for Tool Selection\n\n1. **Session start**: Call \\`read_project_config\\` with the project_root. If it returns\n \\`status: \"not_initialized\"\\`, call \\`toolcairn_init\\` which auto-discovers the stack\n (parses manifests across 12 ecosystems, classifies against the ToolCairn graph, and\n writes \\`.toolcairn/config.json\\`). Then apply the returned setup_steps for CLAUDE.md\n + .mcp.json + .gitignore.\n2. **Before recommending any tool**: Call \\`search_tools\\` first. Never recommend from\n training data alone.\n3. **When user describes a use case**: Call \\`classify_prompt\\`, then \\`refine_requirement\\`\n if tool selection is needed.\n4. **When a tool is selected / replaced / dropped**: Call \\`update_project_config\\` with\n project_root + action — the server atomically updates config.json and appends to\n audit-log.jsonl.\n5. **When encountering an error with a tool**: Call \\`check_issue\\` before debugging —\n it may be a known issue with an open GitHub ticket.\n6. **When user asks to compare tools**: Call \\`compare_tools\\`.\n7. **When user chooses a non-indexed/proprietary tool**: Call \\`update_project_config\\`\n with \\`data: { source: \"non_oss\" }\\`.\n\n### Available ToolCairn MCP Tools\n\n| Tool | When to use |\n|------|------------|\n| \\`classify_prompt\\` | User describes a task — determine if tool search needed |\n| \\`refine_requirement\\` | Decompose vague use case into searchable tool needs |\n| \\`search_tools\\` | Find the best tool for a specific need |\n| \\`search_tools_respond\\` | Answer clarification questions from search_tools |\n| \\`get_stack\\` | Get recommended tool stack for a use case |\n| \\`check_issue\\` | Check if an error is a known tool bug before debugging |\n| \\`check_compatibility\\` | Check if two tools work well together |\n| \\`compare_tools\\` | Compare two tools with health and graph data |\n| \\`report_outcome\\` | Report whether a recommended tool worked (improves future results) |\n| \\`toolcairn_init\\` | One-call project bootstrap (auto-discovers + writes config.json) |\n| \\`read_project_config\\` | Read .toolcairn/config.json from disk (returns structured snapshot) |\n| \\`update_project_config\\` | Apply a mutation (add_tool / remove_tool / update_tool / add_evaluation) |\n| \\`suggest_graph_update\\` | Suggest a new tool or relationship for the ToolCairn graph |\n\n### Rules\n\n- NEVER recommend a tool without first checking ToolCairn unless the tool is already in the project config\n- Always call \\`read_project_config\\` at the start of a session\n- NEVER write to .toolcairn/config.json or .toolcairn/audit-log.jsonl yourself — the server owns them\n- Prefer open-source tools from ToolCairn index; flag proprietary alternatives clearly\n- After selecting a tool, always call \\`update_project_config\\` to persist it\n- After using a tool successfully/unsuccessfully, call \\`report_outcome\\`\n`;\n\nexport function getClaudeInstructions(): InstructionTemplate {\n return {\n file_path: 'CLAUDE.md',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getCursorInstructions(): InstructionTemplate {\n return {\n file_path: '.cursorrules',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getWindsurfInstructions(): InstructionTemplate {\n return {\n file_path: '.windsurfrules',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getCopilotInstructions(): InstructionTemplate {\n return {\n file_path: '.github/copilot-instructions.md',\n mode: 'create',\n content: `# GitHub Copilot Instructions\\n${CORE_RULES}`,\n };\n}\n\nexport function getCopilotCliInstructions(): InstructionTemplate {\n return {\n file_path: '.github/copilot-instructions.md',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getOpenCodeInstructions(): InstructionTemplate {\n return {\n file_path: 'AGENTS.md',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getGenericInstructions(): InstructionTemplate {\n return {\n file_path: 'AI_INSTRUCTIONS.md',\n mode: 'create',\n content: `# AI Assistant Instructions\\n${CORE_RULES}`,\n };\n}\n\nexport function getInstructionsForAgent(agent: AgentType): InstructionTemplate {\n switch (agent) {\n case 'claude':\n return getClaudeInstructions();\n case 'cursor':\n return getCursorInstructions();\n case 'windsurf':\n return getWindsurfInstructions();\n case 'copilot':\n return getCopilotInstructions();\n case 'copilot-cli':\n return getCopilotCliInstructions();\n case 'opencode':\n return getOpenCodeInstructions();\n case 'generic':\n return getGenericInstructions();\n }\n}\n\nexport function getMcpConfigEntry(serverPath?: string): Record<string, unknown> {\n if (serverPath) {\n // Running a locally-built server: node <path> works cross-platform, no wrapper needed\n return {\n toolcairn: {\n command: 'node',\n args: [serverPath],\n },\n };\n }\n return TOOLCAIRN_MCP_ENTRY;\n}\n\n/** Returns OpenCode-specific MCP config (opencode.json format under \"mcp\" key). */\nexport function getOpenCodeMcpEntry(serverPath?: string): Record<string, unknown> {\n if (serverPath) {\n return {\n toolcairn: {\n type: 'local',\n command: ['node', serverPath],\n enabled: true,\n },\n };\n }\n const command = IS_WINDOWS\n ? ['cmd', '/c', 'npx', '-y', '@neurynae/toolcairn-mcp']\n : ['npx', '-y', '@neurynae/toolcairn-mcp'];\n return {\n toolcairn: {\n type: 'local',\n command,\n enabled: true,\n },\n };\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfirmedTool, ToolPilotProjectConfig } from '@toolcairn/types';\nimport { joinAuditPath, joinConfigPath, mutateConfig, readConfig } from '../config-store/index.js';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:read-project-config' });\n\n/** Tools older than this many days are flagged for re-evaluation. */\nconst STALENESS_THRESHOLD_DAYS = 90;\n\nfunction daysSince(isoDate: string): number {\n return (Date.now() - new Date(isoDate).getTime()) / (1000 * 60 * 60 * 24);\n}\n\nexport async function handleReadProjectConfig(args: {\n project_root: string;\n include_locations?: boolean;\n}) {\n try {\n logger.info({ project_root: args.project_root }, 'read_project_config called');\n\n const { config: initial, corrupt_backup_path } = await readConfig(args.project_root);\n\n if (!initial) {\n return okResult({\n status: 'not_initialized',\n project_root: args.project_root,\n config_path: joinConfigPath(args.project_root),\n audit_log_path: joinAuditPath(args.project_root),\n corrupt_backup_path,\n agent_instructions: corrupt_backup_path\n ? `.toolcairn/config.json was unparseable — moved to ${corrupt_backup_path}. Call toolcairn_init with the project_root to re-discover and write a fresh config.`\n : 'No .toolcairn/config.json present. Call toolcairn_init with the project_root to auto-discover the project and bootstrap the config.',\n });\n }\n\n // If the file is v1.0, migrate through mutateConfig (atomic under the lock).\n let config: ToolPilotProjectConfig = initial;\n let migrated = false;\n if (initial.version === '1.0') {\n const result = await mutateConfig(\n args.project_root,\n () => {\n // No-op mutator — migrate() inside mutateConfig handles the upgrade.\n },\n {\n action: 'migrate',\n tool: '__schema__',\n reason: 'Lazy migration on first read after server upgrade',\n },\n );\n config = result.config;\n migrated = true;\n }\n\n const confirmedToolNames = config.tools.confirmed.map((t) => t.name);\n const pendingToolNames = config.tools.pending_evaluation.map((t) => t.name);\n\n const staleTools = config.tools.confirmed\n .filter((t) => {\n const date = t.last_verified ?? t.chosen_at ?? t.confirmed_at;\n return date ? daysSince(date) > STALENESS_THRESHOLD_DAYS : true;\n })\n .map((t) => {\n const date = t.last_verified ?? t.chosen_at ?? t.confirmed_at;\n const days = date ? Math.round(daysSince(date)) : -1;\n return {\n name: t.name,\n last_verified: date ?? 'unknown',\n days_since_verified: days,\n recommendation: 'Consider using check_issue to verify no new known issues',\n };\n });\n\n const non_oss_tools = config.tools.confirmed\n .filter((t) => t.source === 'non_oss')\n .map((t) => t.name);\n\n // Indexed tools: source === 'toolcairn' (current) or 'toolpilot' (legacy pre-rename)\n const toolcairn_indexed_tools = config.tools.confirmed\n .filter((t) => t.source === 'toolcairn' || t.source === 'toolpilot')\n .map((t) => t.name);\n\n const include_locations = args.include_locations === true;\n const confirmed_tools_detail = include_locations\n ? config.tools.confirmed.map((t: ConfirmedTool) => ({\n name: t.name,\n source: t.source,\n canonical_name: t.canonical_name,\n categories: t.categories ?? [],\n match_method: t.match_method ?? 'none',\n github_url: t.github_url,\n locations: t.locations ?? [],\n }))\n : undefined;\n\n const instructions_lines = [\n `Project: ${config.project.name}`,\n config.project.languages && config.project.languages.length > 0\n ? `Languages: ${config.project.languages.map((l) => `${l.name} (${l.file_count} files)`).join(', ')}`\n : '',\n config.project.frameworks && config.project.frameworks.length > 0\n ? `Frameworks: ${config.project.frameworks.map((f) => `${f.name}@${f.workspace}`).join(', ')}`\n : '',\n `Confirmed tools (${confirmedToolNames.length}): ${confirmedToolNames.join(', ') || 'none'}`,\n 'When recommending tools, skip any already in confirmed_tools.',\n non_oss_tools.length > 0\n ? `Non-OSS tools in project (handle separately): ${non_oss_tools.join(', ')}`\n : '',\n staleTools.length > 0\n ? `Tools that may be stale — worth re-checking: ${staleTools.map((t) => t.name).join(', ')}`\n : '',\n ].filter(Boolean);\n\n return okResult({\n status: 'ready',\n schema_version: config.version,\n migrated,\n project: {\n name: config.project.name,\n languages: config.project.languages ?? [],\n frameworks: config.project.frameworks ?? [],\n subprojects: config.project.subprojects ?? [],\n },\n confirmed_tools: confirmedToolNames,\n pending_tools: pendingToolNames,\n non_oss_tools,\n toolcairn_indexed_tools,\n stale_tools: staleTools,\n total_confirmed: confirmedToolNames.length,\n total_pending: pendingToolNames.length,\n last_audit_entry: config.last_audit_entry ?? null,\n scan_metadata: config.scan_metadata ?? null,\n confirmed_tools_detail,\n agent_instructions: instructions_lines.join('\\n'),\n });\n } catch (e) {\n logger.error({ err: e }, 'read_project_config failed');\n return errResult('read_config_error', e instanceof Error ? e.message : String(e));\n }\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfirmedTool, PendingTool, ToolSource } from '@toolcairn/types';\nimport { type PendingAuditEntry, mutateConfig } from '../config-store/index.js';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:update-project-config' });\n\ntype UpdateAction = 'add_tool' | 'remove_tool' | 'update_tool' | 'add_evaluation';\n\nexport async function handleUpdateProjectConfig(args: {\n project_root: string;\n action: UpdateAction;\n tool_name: string;\n data?: Record<string, unknown>;\n}) {\n try {\n logger.info(\n { project_root: args.project_root, action: args.action, tool: args.tool_name },\n 'update_project_config called',\n );\n\n const data = args.data ?? {};\n\n let notFound = false;\n const now = new Date().toISOString();\n\n const audit: PendingAuditEntry = {\n action: args.action,\n tool: args.tool_name,\n reason:\n (data.reason as string | undefined) ??\n (data.chosen_reason as string | undefined) ??\n defaultReasonFor(args.action),\n };\n\n const { config, audit_entry, bootstrapped } = await mutateConfig(\n args.project_root,\n (cfg) => {\n switch (args.action) {\n case 'add_tool': {\n cfg.tools.pending_evaluation = cfg.tools.pending_evaluation.filter(\n (t) => t.name !== args.tool_name,\n );\n if (!cfg.tools.confirmed.some((t) => t.name === args.tool_name)) {\n const tool: ConfirmedTool = {\n name: args.tool_name,\n source: (data.source as ToolSource) ?? 'toolcairn',\n github_url: data.github_url as string | undefined,\n version: data.version as string | undefined,\n chosen_at: now,\n chosen_reason: (data.chosen_reason as string) ?? 'Selected via ToolCairn',\n alternatives_considered: (data.alternatives_considered as string[]) ?? [],\n query_id: data.query_id as string | undefined,\n notes: data.notes as string | undefined,\n locations: [],\n };\n cfg.tools.confirmed.push(tool);\n }\n break;\n }\n case 'remove_tool': {\n cfg.tools.confirmed = cfg.tools.confirmed.filter((t) => t.name !== args.tool_name);\n cfg.tools.pending_evaluation = cfg.tools.pending_evaluation.filter(\n (t) => t.name !== args.tool_name,\n );\n break;\n }\n case 'update_tool': {\n const idx = cfg.tools.confirmed.findIndex((t) => t.name === args.tool_name);\n if (idx === -1) {\n notFound = true;\n return;\n }\n const existing = cfg.tools.confirmed[idx];\n if (!existing) {\n notFound = true;\n return;\n }\n cfg.tools.confirmed[idx] = {\n ...existing,\n ...(data.version !== undefined ? { version: data.version as string } : {}),\n ...(data.notes !== undefined ? { notes: data.notes as string } : {}),\n ...(data.chosen_reason !== undefined\n ? { chosen_reason: data.chosen_reason as string }\n : {}),\n ...(data.alternatives_considered !== undefined\n ? { alternatives_considered: data.alternatives_considered as string[] }\n : {}),\n last_verified: now,\n };\n break;\n }\n case 'add_evaluation': {\n const inConfirmed = cfg.tools.confirmed.some((t) => t.name === args.tool_name);\n const inPending = cfg.tools.pending_evaluation.some((t) => t.name === args.tool_name);\n if (!inConfirmed && !inPending) {\n const pending: PendingTool = {\n name: args.tool_name,\n category: (data.category as string) ?? 'other',\n added_at: now,\n };\n cfg.tools.pending_evaluation.push(pending);\n }\n break;\n }\n }\n },\n audit,\n );\n\n if (notFound) {\n return errResult(\n 'not_found',\n `Tool \"${args.tool_name}\" is not in the confirmed list — cannot update.`,\n );\n }\n\n return okResult({\n action_applied: args.action,\n tool_name: args.tool_name,\n confirmed_count: config.tools.confirmed.length,\n pending_count: config.tools.pending_evaluation.length,\n last_audit_entry: audit_entry,\n bootstrapped,\n config_path: '.toolcairn/config.json',\n audit_log_path: '.toolcairn/audit-log.jsonl',\n });\n } catch (e) {\n logger.error({ err: e }, 'update_project_config failed');\n return errResult('update_config_error', e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction defaultReasonFor(action: UpdateAction): string {\n switch (action) {\n case 'add_tool':\n return 'Added via ToolCairn recommendation';\n case 'remove_tool':\n return 'Removed from project';\n case 'update_tool':\n return 'Tool details updated';\n case 'add_evaluation':\n return 'Added for evaluation';\n }\n}\n","/**\n * MCP Event Logger Middleware\n *\n * Wraps tool handlers to record timing, status, and metadata to:\n * 1. POST /v1/events on the ToolCairn API (queryable via DB — McpEvent table)\n * 2. TOOLCAIRN_EVENTS_PATH JSONL file (for standalone tracker.html)\n *\n * All writes are fire-and-forget — NEVER block a tool response.\n * If TOOLCAIRN_TRACKING_ENABLED=false (or unset), all logging is skipped.\n */\n\nimport { appendFile, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { config } from '@toolcairn/config';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { loadCredentials } from '@toolcairn/remote';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server:event-logger' });\n\nfunction isTrackingEnabled(): boolean {\n return process.env.TOOLCAIRN_TRACKING_ENABLED !== 'false';\n}\n\nfunction getEventsPath(): string | null {\n return process.env.TOOLCAIRN_EVENTS_PATH ?? null;\n}\n\ninterface McpEventRecord {\n id: string;\n tool_name: string;\n query_id: string | null;\n duration_ms: number;\n status: 'ok' | 'error';\n metadata: Record<string, unknown> | null;\n created_at: string;\n}\n\nfunction extractQueryId(args: Record<string, unknown>): string | null {\n if (typeof args.query_id === 'string') return args.query_id;\n return null;\n}\n\nfunction extractMetadata(toolName: string, result: CallToolResult): Record<string, unknown> | null {\n try {\n const text = result.content?.[0];\n if (text?.type !== 'text') return null;\n const parsed = JSON.parse(text.text) as Record<string, unknown>;\n const data = parsed.data as Record<string, unknown> | undefined;\n\n // Extract lightweight summary metadata — never store full results\n const meta: Record<string, unknown> = { tool: toolName };\n\n if (data) {\n if ('status' in data) meta.status = data.status;\n if ('total_confirmed' in data) meta.total_confirmed = data.total_confirmed;\n if ('staged' in data) meta.staged = data.staged;\n if ('auto_graduated' in data) meta.auto_graduated = data.auto_graduated;\n if ('is_two_option' in data) meta.is_two_option = data.is_two_option;\n if ('non_indexed_guidance' in data) meta.had_non_indexed_guidance = true;\n if ('credibility_warning' in data) meta.had_credibility_warning = true;\n if ('deprecation_warning' in data && data.deprecation_warning) {\n meta.had_deprecation_warning = true;\n }\n if ('recommendation' in data) meta.recommendation = data.recommendation;\n if ('compatibility_signal' in data) meta.compatibility_signal = data.compatibility_signal;\n if ('index_queued' in data) meta.index_queued = data.index_queued;\n }\n\n return meta;\n } catch {\n return null;\n }\n}\n\nasync function writeToFile(eventsPath: string, event: McpEventRecord): Promise<void> {\n try {\n await mkdir(dirname(eventsPath), { recursive: true });\n await appendFile(eventsPath, `${JSON.stringify(event)}\\n`, 'utf-8');\n } catch (e) {\n logger.warn({ err: e, path: eventsPath }, 'Failed to write event to JSONL file');\n }\n}\n\nasync function sendToApi(event: McpEventRecord): Promise<void> {\n try {\n const creds = await loadCredentials();\n if (!creds) return;\n\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (creds.access_token) headers.Authorization = `Bearer ${creds.access_token}`;\n if (creds.client_id) headers['X-ToolCairn-Key'] = creds.client_id;\n\n await fetch(`${config.TOOLPILOT_API_URL}/v1/events`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n tool_name: event.tool_name,\n query_id: event.query_id,\n duration_ms: event.duration_ms,\n status: event.status,\n metadata: event.metadata,\n }),\n });\n } catch (e) {\n logger.debug({ err: e }, 'Failed to send event to API — non-fatal');\n }\n}\n\ntype ToolHandler<TArgs> = (args: TArgs) => Promise<CallToolResult>;\n\n/**\n * Wrap a tool handler with event logging.\n * The wrapper captures timing and status, then fires off async writes.\n */\nexport function withEventLogging<TArgs extends Record<string, unknown>>(\n toolName: string,\n handler: ToolHandler<TArgs>,\n): ToolHandler<TArgs> {\n return async (args: TArgs): Promise<CallToolResult> => {\n if (!isTrackingEnabled()) {\n return handler(args);\n }\n\n const start = Date.now();\n let result: CallToolResult | undefined;\n let status: 'ok' | 'error' = 'ok';\n\n try {\n result = await handler(args);\n if (result.isError) status = 'error';\n } catch (e) {\n status = 'error';\n throw e;\n } finally {\n const duration_ms = Date.now() - start;\n const event: McpEventRecord = {\n id: crypto.randomUUID(),\n tool_name: toolName,\n query_id: extractQueryId(args),\n duration_ms,\n status,\n metadata: result ? extractMetadata(toolName, result) : null,\n created_at: new Date().toISOString(),\n };\n\n // Fire-and-forget: API + local file (never block the tool response)\n sendToApi(event).catch(() => {});\n\n const eventsPath = getEventsPath();\n if (eventsPath) {\n writeToFile(eventsPath, event).catch(() => {});\n }\n }\n\n // result is always assigned in the try block above; undefined path is unreachable\n return result ?? { content: [], isError: true };\n };\n}\n","import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { config } from '@toolcairn/config';\n\nexport function createTransport(): Transport {\n if (process.env.MCP_TRANSPORT === 'http') {\n return new StreamableHTTPServerTransport({\n sessionIdGenerator: () => crypto.randomUUID(),\n });\n }\n return new StdioServerTransport();\n}\n\nexport { config };\n"],"mappings":"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BAAoB,YAA4B;AAC9D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAwJa,KAAK,UAAU,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["NetworkError","AuthError","createMcpLogger","withErrorHandling","logger","import_config","import_errors","McpServer","path","import_errors","platform","resolve","z","import_errors","mkdir","writeFile","join","join","mkdir","writeFile","import_config","import_errors","import_errors","logger","import_errors","join","join","import_errors","readFile","join","access","path","logger","readFile","join","import_errors","mkdir","logger","config","mkdir","import_errors","mkdir","readFile","writeFile","writeFileAtomic","logger","mkdir","readFile","writeFileAtomic","logger","config","import_errors","mkdir","writeFile","logger","config","mkdir","writeFile","import_errors","readFile","readdir","join","join","readdir","readdir","join","readdir","join","readFile","join","join","readFile","readFile","join","join","readFile","readFile","join","extractDeps","join","readFile","readFile","readdir","join","relative","readdir","path","join","readFile","relative","readFile","join","join","readFile","readFile","join","config","join","readFile","path","readFile","join","XMLParser","toArray","join","readFile","XMLParser","readFile","join","join","readFile","readFile","join","parseYaml","SECTION_MAP","join","readFile","parseYaml","readFile","join","parseToml","join","parseToml","readFile","path","readFile","join","join","readFile","readFile","join","join","readFile","readdir","join","relative","sep","readdir","join","relative","sep","readFile","join","parseToml","parseYaml","join","parseYaml","readFile","parseToml","logger","name","readFile","logger","config","import_errors","logger","config","import_errors","logger","config","z","import_errors","appendFile","mkdir","logger","mkdir","appendFile","logger","z","import_config","logger","McpServer","z"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/esm_shims.js","../../../packages/config/src/index.ts","../../../packages/errors/src/error-codes.ts","../../../packages/errors/src/errors.ts","../../../packages/errors/src/serializers.ts","../../../packages/errors/src/logger.ts","../../../packages/errors/src/mcp-error-wrapper.ts","../../../packages/errors/src/index.ts","../src/index.prod.ts","../../../packages/remote/src/index.ts","../../../packages/remote/src/client.ts","../../../packages/remote/src/credentials.ts","../../../packages/remote/src/device-auth.ts","../src/project-setup.ts","../src/tools/generate-tracker.ts","../src/server.prod.ts","../../../packages/tools-local/src/index.ts","../../../packages/tools-local/src/schemas.ts","../../../packages/tools-local/src/utils.ts","../../../packages/tools-local/src/handlers/classify-prompt.ts","../../../packages/tools-local/src/handlers/toolcairn-init.ts","../../../packages/tools-local/src/config-store/index.ts","../../../packages/tools-local/src/config-store/paths.ts","../../../packages/tools-local/src/config-store/read.ts","../../../packages/tools-local/src/discovery/util/fs.ts","../../../packages/tools-local/src/config-store/write.ts","../../../packages/tools-local/src/config-store/audit.ts","../../../packages/tools-local/src/config-store/migrate.ts","../../../packages/tools-local/src/config-store/mutate.ts","../../../packages/tools-local/src/config-store/skeleton.ts","../../../packages/tools-local/src/discovery/index.ts","../../../packages/tools-local/src/discovery/scan-project.ts","../../../packages/tools-local/src/discovery/ecosystem-detect.ts","../../../packages/tools-local/src/discovery/frameworks/detect.ts","../../../packages/tools-local/src/discovery/language-detect.ts","../../../packages/tools-local/src/discovery/parsers/index.ts","../../../packages/tools-local/src/discovery/parsers/cargo.ts","../../../packages/tools-local/src/discovery/parsers/composer.ts","../../../packages/tools-local/src/discovery/parsers/dart.ts","../../../packages/tools-local/src/discovery/parsers/dotnet.ts","../../../packages/tools-local/src/discovery/parsers/go.ts","../../../packages/tools-local/src/discovery/parsers/gradle.ts","../../../packages/tools-local/src/discovery/parsers/maven.ts","../../../packages/tools-local/src/discovery/parsers/mix.ts","../../../packages/tools-local/src/discovery/parsers/npm.ts","../../../packages/tools-local/src/discovery/parsers/pypi.ts","../../../packages/tools-local/src/discovery/parsers/ruby.ts","../../../packages/tools-local/src/discovery/parsers/swift.ts","../../../packages/tools-local/src/discovery/resolvers/index.ts","../../../packages/tools-local/src/discovery/resolvers/cargo.ts","../../../packages/tools-local/src/discovery/resolvers/url-normalise.ts","../../../packages/tools-local/src/discovery/resolvers/composer.ts","../../../packages/tools-local/src/discovery/resolvers/go.ts","../../../packages/tools-local/src/discovery/resolvers/gradle.ts","../../../packages/tools-local/src/discovery/resolvers/pom-shared.ts","../../../packages/tools-local/src/discovery/resolvers/hex.ts","../../../packages/tools-local/src/discovery/resolvers/maven.ts","../../../packages/tools-local/src/discovery/resolvers/npm.ts","../../../packages/tools-local/src/discovery/resolvers/nuget.ts","../../../packages/tools-local/src/discovery/resolvers/pub.ts","../../../packages/tools-local/src/discovery/resolvers/pypi.ts","../../../packages/tools-local/src/discovery/resolvers/ruby.ts","../../../packages/tools-local/src/discovery/resolvers/swift-pm.ts","../../../packages/tools-local/src/discovery/workspaces/glob.ts","../../../packages/tools-local/src/discovery/workspaces/walker.ts","../../../packages/tools-local/src/templates/agent-instructions.ts","../../../packages/tools-local/src/handlers/read-project-config.ts","../../../packages/tools-local/src/handlers/update-project-config.ts","../src/middleware/event-logger.ts","../src/transport.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { z } from 'zod';\n\nconst configSchema = z.object({\n // ── MCP Server ────────────────────────────────────────────────────────────\n MCP_SERVER_PORT: z.coerce.number().int().positive().default(3001),\n MCP_SERVER_HOST: z.string().default('0.0.0.0'),\n\n // ── Deployment Mode ───────────────────────────────────────────────────────\n /** dev: direct Docker DB connections | production: HTTP client to remote API */\n TOOLPILOT_MODE: z.enum(['dev', 'staging', 'production']).default('dev'),\n /** URL of the ToolCairn HTTP API (used when TOOLPILOT_MODE=production) */\n TOOLPILOT_API_URL: z.string().default('https://api.neurynae.com'),\n\n // ── General ───────────────────────────────────────────────────────────────\n NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n});\n\nexport type Config = z.infer<typeof configSchema>;\n\nfunction loadConfig(): Config {\n const result = configSchema.safeParse(process.env);\n if (!result.success) {\n console.error('❌ Invalid environment configuration:');\n console.error(result.error.format());\n process.exit(1);\n }\n return result.data;\n}\n\n/** Validated, typed configuration loaded from environment variables. */\nexport const config: Config = loadConfig();\n","/**\n * Canonical error code catalog.\n * All AppError subclasses set one of these codes.\n * Codes are stable string constants — safe to log, persist, and return to clients.\n */\nexport const ErrorCode = {\n // ── Database ────────────────────────────────────────────────────────────────\n ERR_DB_CONNECTION: 'ERR_DB_CONNECTION',\n ERR_DB_QUERY: 'ERR_DB_QUERY',\n ERR_DB_TIMEOUT: 'ERR_DB_TIMEOUT',\n ERR_DB_CONSTRAINT: 'ERR_DB_CONSTRAINT',\n ERR_DB_NOT_FOUND: 'ERR_DB_NOT_FOUND',\n\n // ── Validation ──────────────────────────────────────────────────────────────\n ERR_VALIDATION_INPUT: 'ERR_VALIDATION_INPUT',\n ERR_VALIDATION_SCHEMA: 'ERR_VALIDATION_SCHEMA',\n\n // ── Auth ────────────────────────────────────────────────────────────────────\n ERR_AUTH_TOKEN_EXPIRED: 'ERR_AUTH_TOKEN_EXPIRED',\n ERR_AUTH_UNAUTHORIZED: 'ERR_AUTH_UNAUTHORIZED',\n ERR_AUTH_FORBIDDEN: 'ERR_AUTH_FORBIDDEN',\n\n // ── External services ───────────────────────────────────────────────────────\n ERR_EXTERNAL_GITHUB: 'ERR_EXTERNAL_GITHUB',\n ERR_EXTERNAL_NOMIC: 'ERR_EXTERNAL_NOMIC',\n ERR_EXTERNAL_QDRANT: 'ERR_EXTERNAL_QDRANT',\n ERR_EXTERNAL_MEMGRAPH: 'ERR_EXTERNAL_MEMGRAPH',\n ERR_EXTERNAL_RAZORPAY: 'ERR_EXTERNAL_RAZORPAY',\n\n // ── Queue ───────────────────────────────────────────────────────────────────\n ERR_QUEUE_PUBLISH: 'ERR_QUEUE_PUBLISH',\n ERR_QUEUE_CONSUME: 'ERR_QUEUE_CONSUME',\n ERR_QUEUE_TIMEOUT: 'ERR_QUEUE_TIMEOUT',\n\n // ── Search ──────────────────────────────────────────────────────────────────\n ERR_SEARCH_PIPELINE: 'ERR_SEARCH_PIPELINE',\n ERR_SEARCH_EMBEDDING: 'ERR_SEARCH_EMBEDDING',\n ERR_SEARCH_NO_RESULTS: 'ERR_SEARCH_NO_RESULTS',\n\n // ── Indexer ─────────────────────────────────────────────────────────────────\n ERR_INDEXER_CRAWL: 'ERR_INDEXER_CRAWL',\n ERR_INDEXER_PROCESS: 'ERR_INDEXER_PROCESS',\n ERR_INDEXER_WRITE: 'ERR_INDEXER_WRITE',\n\n // ── Network ─────────────────────────────────────────────────────────────────\n ERR_NETWORK_TIMEOUT: 'ERR_NETWORK_TIMEOUT',\n ERR_NETWORK_UNREACHABLE: 'ERR_NETWORK_UNREACHABLE',\n\n // ── MCP ─────────────────────────────────────────────────────────────────────\n ERR_MCP_HANDLER: 'ERR_MCP_HANDLER',\n ERR_MCP_AUTH: 'ERR_MCP_AUTH',\n\n // ── Generic ─────────────────────────────────────────────────────────────────\n ERR_INTERNAL: 'ERR_INTERNAL',\n ERR_NOT_FOUND: 'ERR_NOT_FOUND',\n ERR_RATE_LIMIT: 'ERR_RATE_LIMIT',\n} as const;\n\nexport type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode];\n","import { ErrorCode, type ErrorCodeValue } from './error-codes.js';\nimport type { ErrorContext, Severity } from './types.js';\n\nexport interface AppErrorOptions {\n code: ErrorCodeValue;\n message: string;\n /** HTTP status code to return to the client. Default: 500 */\n httpStatus?: number;\n /** How severe is this error for alerting/triage. Default: 'medium' */\n severity?: Severity;\n /**\n * Operational errors are expected conditions (validation failure, rate limit,\n * not found). Their message is safe to expose to clients.\n *\n * Non-operational errors are programmer bugs (null reference, type error).\n * Their message must be masked — only a generic \"internal error\" reaches clients.\n *\n * Default: true\n */\n isOperational?: boolean;\n /** The underlying error that caused this one — preserves the full chain */\n cause?: unknown;\n /** Structured context: module, operation, IDs — logged alongside the error */\n context?: ErrorContext;\n}\n\n/**\n * Base application error. All domain errors extend this.\n *\n * Carries structured metadata for:\n * - Deterministic error codes (safe to log, persist, return to clients)\n * - Severity-based alerting\n * - Operational vs programmer error distinction\n * - Rich context for debugging (module, operation, IDs)\n * - Full cause chain via Error.cause (ES2022)\n */\nexport class AppError extends Error {\n public readonly code: ErrorCodeValue;\n public readonly httpStatus: number;\n public readonly severity: Severity;\n public readonly isOperational: boolean;\n public readonly context: ErrorContext;\n public readonly timestamp: string;\n\n constructor(opts: AppErrorOptions) {\n super(opts.message, { cause: opts.cause });\n this.name = this.constructor.name;\n this.code = opts.code;\n this.httpStatus = opts.httpStatus ?? 500;\n this.severity = opts.severity ?? 'medium';\n this.isOperational = opts.isOperational ?? true;\n this.context = opts.context ?? {};\n this.timestamp = new Date().toISOString();\n\n // Restore correct prototype chain — required for `instanceof` checks to\n // work correctly when compiling to CommonJS with TypeScript.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** Structured JSON representation used by the pino error serializer */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n httpStatus: this.httpStatus,\n severity: this.severity,\n isOperational: this.isOperational,\n context: this.context,\n timestamp: this.timestamp,\n stack: this.stack,\n cause:\n this.cause instanceof Error\n ? { name: this.cause.name, message: this.cause.message, stack: this.cause.stack }\n : this.cause,\n };\n }\n}\n\n// ── Domain error classes ──────────────────────────────────────────────────────\n// Each sets sensible defaults so call sites stay concise.\n\nexport class DatabaseError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_DB_QUERY,\n message: opts.message,\n httpStatus: 503,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class NetworkError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_NETWORK_TIMEOUT,\n message: opts.message,\n httpStatus: 502,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class ValidationError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_VALIDATION_INPUT,\n message: opts.message,\n httpStatus: 400,\n severity: 'low',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class AuthError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_AUTH_UNAUTHORIZED,\n message: opts.message,\n httpStatus: 401,\n severity: 'medium',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class ExternalServiceError extends AppError {\n constructor(opts: {\n service: string;\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_INTERNAL,\n message: `[${opts.service}] ${opts.message}`,\n httpStatus: 502,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: { ...opts.context, service: opts.service },\n });\n }\n}\n\nexport class QueueError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_QUEUE_PUBLISH,\n message: opts.message,\n httpStatus: 503,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class SearchError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_SEARCH_PIPELINE,\n message: opts.message,\n httpStatus: 500,\n severity: 'medium',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class IndexerError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_INDEXER_PROCESS,\n message: opts.message,\n httpStatus: 500,\n severity: 'medium',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n\nexport class VectorError extends AppError {\n constructor(opts: {\n code?: ErrorCodeValue;\n message: string;\n cause?: unknown;\n context?: ErrorContext;\n }) {\n super({\n code: opts.code ?? ErrorCode.ERR_EXTERNAL_NOMIC,\n message: opts.message,\n httpStatus: 502,\n severity: 'high',\n isOperational: true,\n cause: opts.cause,\n context: opts.context,\n });\n }\n}\n","import { AppError } from './errors.js';\n\n/**\n * Custom pino error serializer.\n *\n * When pino logs an object with an `err` or `error` field, it runs it through\n * this serializer. AppError instances get full structured metadata extracted.\n * Plain Error instances get standard fields. Non-Error values are stringified.\n *\n * Usage in logger options:\n * serializers: { err: errorSerializer, error: errorSerializer }\n */\nexport function errorSerializer(err: unknown): Record<string, unknown> {\n if (err instanceof AppError) {\n return err.toJSON();\n }\n\n if (err instanceof Error) {\n return {\n name: err.name,\n message: err.message,\n stack: err.stack,\n cause:\n err.cause instanceof Error\n ? { name: err.cause.name, message: err.cause.message, stack: err.cause.stack }\n : err.cause,\n };\n }\n\n return { message: String(err) };\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport pino, { type Logger, type LoggerOptions } from 'pino';\nimport { errorSerializer } from './serializers.js';\n\nconst REDACT_PATHS = [\n 'password',\n 'token',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n 'apiKey',\n 'api_key',\n 'secret',\n 'TOOLPILOT_API_KEY',\n 'authorization',\n 'cookie',\n '*.password',\n '*.token',\n '*.secret',\n '*.apiKey',\n '*.api_key',\n];\n\nexport interface CreateLoggerOptions {\n /** Module name used in every log line, e.g. '@toolcairn/mcp-server' */\n name: string;\n /** Override the environment-driven log level */\n level?: string;\n /** Additional fields merged into every log line's base object */\n defaultFields?: Record<string, unknown>;\n}\n\n/**\n * Creates a pino logger for use inside the MCP server.\n *\n * IMPORTANT: The MCP JSON-RPC protocol communicates over stdout.\n * All logging MUST go to stderr (fd=2) to avoid corrupting the protocol stream.\n *\n * In production the logger writes to two targets:\n * 1. stderr — all messages at the configured level (visible via `npx toolcairn-mcp 2>/dev/null`)\n * 2. ~/.toolcairn/logs/mcp-error-YYYY-MM-DD.log — warn+ messages for post-hoc debugging\n *\n * In development (NODE_ENV !== 'production') the file transport is omitted to\n * avoid cluttering the user's home directory during testing.\n */\nexport function createMcpLogger(opts: CreateLoggerOptions): Logger {\n const level =\n opts.level ??\n process.env.LOG_LEVEL ??\n (process.env.NODE_ENV !== 'production' ? 'debug' : 'info');\n\n const pinoOpts: LoggerOptions = {\n name: opts.name,\n level,\n serializers: {\n err: errorSerializer,\n error: errorSerializer,\n },\n redact: {\n paths: REDACT_PATHS,\n censor: '[REDACTED]',\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n base: {\n pid: process.pid,\n ...opts.defaultFields,\n },\n };\n\n const isProd = process.env.NODE_ENV === 'production';\n\n if (!isProd) {\n // Dev: stderr only, no file pollution\n return pino({ ...pinoOpts, transport: { target: 'pino/file', options: { destination: 2 } } });\n }\n\n // Production: stderr + persistent error log file\n const logDir = join(homedir(), '.toolcairn', 'logs');\n const today = new Date().toISOString().slice(0, 10);\n const errorLogPath = join(logDir, `mcp-error-${today}.log`);\n\n const transport = pino.transport({\n targets: [\n { target: 'pino/file', options: { destination: 2 }, level },\n { target: 'pino/file', options: { destination: errorLogPath, mkdir: true }, level: 'warn' },\n ],\n });\n\n return pino(pinoOpts, transport);\n}\n\n/** Alias for convenience — use createMcpLogger as the standard factory in MCP packages */\nexport { createMcpLogger as createLogger };\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { Logger } from 'pino';\nimport { ErrorCode } from './error-codes.js';\nimport { AppError } from './errors.js';\n\n/**\n * Wraps an MCP tool handler with structured error handling.\n *\n * Without this wrapper, an uncaught throw inside a tool handler crashes the\n * entire MCP server session. With it:\n * - AppError instances are caught, logged at appropriate severity, and returned\n * as a proper MCP CallToolResult with isError=true\n * - Unknown errors are caught, logged at 'error', and returned with a generic\n * ERR_MCP_HANDLER code\n *\n * The handler itself is responsible for returning CallToolResult on expected\n * failures (validation, not-found). This wrapper is a safety net for unexpected\n * exceptions that escape normal control flow.\n *\n * Compose with withEventLogging from event-logger.ts — this wrapper goes INSIDE\n * the event logger so errors are both logged and recorded as events:\n *\n * withEventLogging('search_tools', withErrorHandling('search_tools', logger, handler))\n */\nexport function withErrorHandling<TArgs>(\n toolName: string,\n logger: Logger,\n handler: (args: TArgs) => Promise<CallToolResult>,\n): (args: TArgs) => Promise<CallToolResult> {\n return async (args: TArgs): Promise<CallToolResult> => {\n try {\n return await handler(args);\n } catch (err) {\n if (err instanceof AppError) {\n const logLevel = err.severity === 'critical' || err.severity === 'high' ? 'error' : 'warn';\n\n logger[logLevel]({ err, tool: toolName }, `Tool ${toolName} failed: ${err.message}`);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n ok: false,\n error: err.code,\n message: err.isOperational ? err.message : 'An internal error occurred',\n }),\n },\n ],\n isError: true,\n };\n }\n\n // Unknown/programmer error\n logger.error({ err, tool: toolName }, `Unexpected error in tool ${toolName}`);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n ok: false,\n error: ErrorCode.ERR_MCP_HANDLER,\n message: err instanceof Error ? err.message : String(err),\n }),\n },\n ],\n isError: true,\n };\n }\n };\n}\n","export { ErrorCode, type ErrorCodeValue } from './error-codes.js';\nexport type { ErrorContext, Severity } from './types.js';\nexport {\n AppError,\n type AppErrorOptions,\n DatabaseError,\n NetworkError,\n ValidationError,\n AuthError,\n ExternalServiceError,\n QueueError,\n SearchError,\n IndexerError,\n VectorError,\n} from './errors.js';\nexport { errorSerializer } from './serializers.js';\nexport { createMcpLogger, createLogger, type CreateLoggerOptions } from './logger.js';\nexport { withErrorHandling } from './mcp-error-wrapper.js';\n","/**\n * Production-only entry point for the published npm bundle.\n *\n * Auth flow (automatic, survives restarts, no reconnect needed):\n * - Valid token → buildProdServer() — all 14 tools immediately\n * - No token, pending-auth.json exists (previous process was killed mid-poll):\n * → Resume polling; browser already open — don't open again\n * - No token, no pending auth:\n * → Request new device code, persist to pending-auth.json\n * → Open browser, show URL + code in instructions\n * → Poll in background; when confirmed: dynamically add all 14 tools\n * to the running server (notifications/tools/list_changed sent to client)\n * → No reconnect required\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { config } from '@toolcairn/config';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport {\n isTokenValid,\n loadCredentials,\n loadPendingAuth,\n requestDeviceCode,\n startDeviceAuth,\n} from '@toolcairn/remote';\nimport { z } from 'zod';\nimport { ensureProjectSetup } from './project-setup.js';\nimport { addToolsToServer, buildProdServer } from './server.prod.js';\nimport { createTransport } from './transport.js';\n\nprocess.env.TOOLPILOT_MODE = 'production';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server' });\n\nasync function main(): Promise<void> {\n await ensureProjectSetup();\n\n const creds = await loadCredentials();\n const authenticated = creds !== null && isTokenValid(creds);\n\n let server: McpServer;\n\n if (authenticated) {\n logger.info({ user: creds.user_email }, 'Authenticated — starting full server');\n server = await buildProdServer();\n } else {\n let verificationUri = 'https://toolcairn.neurynae.com/signup';\n let userCode = '';\n\n try {\n const pending = await loadPendingAuth();\n if (pending) {\n // Resume from previous process — browser already open, just poll\n verificationUri = pending.verification_uri;\n userCode = pending.user_code;\n logger.info({ userCode }, 'Resuming pending sign-in');\n } else {\n // Fresh start — request new device code + open browser\n const codeData = await requestDeviceCode(config.TOOLPILOT_API_URL);\n verificationUri = codeData.verification_uri;\n userCode = codeData.user_code;\n logger.info({ userCode }, 'New sign-in started');\n }\n } catch (err) {\n logger.error({ err }, 'Could not reach ToolCairn API — check your connection');\n }\n\n const instructions = userCode\n ? `# ToolCairn — Sign In Required\\n\\nA browser window should have opened automatically.\\n\\n**Sign-in URL:** ${verificationUri}\\n**Code to confirm:** \\`${userCode}\\`\\n\\nOpen the URL, sign in, and confirm the code shown. All 14 tools will appear automatically — no restart needed.`\n : '# ToolCairn — Sign In Required\\n\\nVisit https://toolcairn.neurynae.com to create an account, then reconnect.';\n\n server = new McpServer({ name: 'toolcairn', version: '0.1.0' }, { instructions });\n\n server.registerTool(\n 'toolcairn_auth',\n {\n description: 'Check ToolCairn sign-in status.',\n inputSchema: z.object({ action: z.enum(['status']) }),\n },\n async () => ({\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n authenticated: false,\n sign_in_url: verificationUri,\n code: userCode || null,\n message: userCode\n ? `Open ${verificationUri} and confirm code \"${userCode}\". Tools will appear automatically when confirmed.`\n : 'Visit toolcairn.neurynae.com to sign up.',\n }),\n },\n ],\n }),\n );\n\n // Start auth flow in background.\n // On success: dynamically register all 14 tools on this same server.\n // The MCP SDK sends notifications/tools/list_changed — client refreshes\n // the tool list automatically, no reconnect required.\n startDeviceAuth(config.TOOLPILOT_API_URL)\n .then(async () => {\n logger.info('Sign-in complete — adding all tools to running server');\n try {\n await addToolsToServer(server);\n logger.info('All ToolCairn tools now available');\n } catch (err) {\n logger.error({ err }, 'Failed to add tools after sign-in — please reconnect');\n }\n })\n .catch((err: unknown) => {\n logger.error({ err }, 'Sign-in failed — please try again');\n });\n }\n\n const transport = createTransport();\n await server.connect(transport);\n logger.info(authenticated ? 'ToolCairn MCP ready' : 'ToolCairn MCP ready (awaiting sign-in)');\n}\n\nmain().catch((error: unknown) => {\n createMcpLogger({ name: '@toolcairn/mcp-server' }).error(\n { err: error },\n 'Failed to start MCP server',\n );\n process.exit(1);\n});\n","export { ToolCairnClient } from './client.js';\nexport type { ToolCairnClientOptions } from './client.js';\nexport {\n loadCredentials,\n loadOrCreateCredentials,\n saveCredentials,\n getApiKey,\n upgradeToAuthenticated,\n clearAuthentication,\n isTokenValid,\n savePendingAuth,\n loadPendingAuth,\n clearPendingAuth,\n} from './credentials.js';\nexport type { Credentials, PendingAuth } from './credentials.js';\nexport { startDeviceAuth, requestDeviceCode } from './device-auth.js';\n","/**\n * ToolCairnClient — HTTP client used by the thin npm MCP package.\n *\n * Makes one POST request per remote tool call to the ToolCairn API\n * (sitting behind a Cloudflare Worker in production, or directly in dev).\n *\n * Returns CallToolResult so the MCP server can pass responses through unchanged.\n */\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { ErrorCode } from '@toolcairn/errors';\nimport type { DiscoveryWarning, Ecosystem, MatchMethod } from '@toolcairn/types';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface ToolCairnClientOptions {\n /** Base URL of the ToolCairn API, e.g. https://api.neurynae.com */\n baseUrl: string;\n /** Anonymous API key (UUID) sent in X-ToolCairn-Key header */\n apiKey: string;\n /** Optional JWT access token — sent as Authorization: Bearer when present */\n accessToken?: string;\n /** Request timeout in ms (default 30s) */\n timeoutMs?: number;\n}\n\nexport class ToolCairnClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeoutMs: number;\n\n private readonly accessToken?: string;\n\n constructor(opts: ToolCairnClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.apiKey = opts.apiKey;\n this.accessToken = opts.accessToken;\n this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n // ── Core Search ──────────────────────────────────────────────────────────\n\n async searchTools(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/search', args);\n }\n\n async searchToolsRespond(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/search/respond', args);\n }\n\n // ── Graph ────────────────────────────────────────────────────────────────\n\n async checkCompatibility(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/graph/compatibility', args);\n }\n\n async compareTools(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/graph/compare', args);\n }\n\n async getStack(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/graph/stack', args);\n }\n\n // ── Intelligence ─────────────────────────────────────────────────────────\n\n async refineRequirement(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/intelligence/refine', args);\n }\n\n async verifySuggestion(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/intelligence/verify', args);\n }\n\n async checkIssue(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/intelligence/issue', args);\n }\n\n // ── Tool resolution ──────────────────────────────────────────────────────\n\n /**\n * Classify a batch of (ecosystem, name) tuples against the ToolCairn graph.\n *\n * Used by the discovery pipeline inside `toolcairn_init` — NOT exposed as an\n * MCP tool to the agent. Returns typed data, not CallToolResult.\n *\n * Graceful degradation:\n * - HTTP 404 (endpoint not deployed yet): returns all inputs as unmatched,\n * with a warning.\n * - Network error / timeout: same.\n * - HTTP 200 but malformed body: logs a warning, returns unmatched.\n *\n * Caller (scan-project) uses the unmatched results to classify tools as\n * `source: \"non_oss\"` and still returns a valid scan.\n */\n async batchResolve(\n items: Array<{\n name: string;\n ecosystem: Ecosystem;\n canonical_package_name?: string;\n github_url?: string;\n }>,\n ): Promise<{\n results: Array<{\n input: { name: string; ecosystem: Ecosystem };\n matched: boolean;\n match_method: MatchMethod;\n tool?: { canonical_name: string; github_url: string; categories: string[] };\n }>;\n warnings: DiscoveryWarning[];\n methods: Map<string, MatchMethod>;\n githubUrls: Map<string, string>;\n }> {\n const warnings: DiscoveryWarning[] = [];\n const methods = new Map<string, MatchMethod>();\n const githubUrls = new Map<string, string>();\n\n if (items.length === 0) {\n return { results: [], warnings, methods, githubUrls };\n }\n\n try {\n const res = await this.rawPost('/v1/tools/batch-resolve', {\n api_version: '1',\n tools: items,\n });\n\n if (res.status === 404) {\n warnings.push({\n scope: 'batch-resolve',\n message:\n '/v1/tools/batch-resolve not deployed on this engine — falling back to offline classification (source: non_oss).',\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n\n if (!res.ok) {\n warnings.push({\n scope: 'batch-resolve',\n message: `batch-resolve returned HTTP ${res.status} — all tools marked as non_oss.`,\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n\n const body = (await res.json()) as {\n resolved?: Array<{\n input: { name: string; ecosystem: Ecosystem };\n matched?: boolean;\n match_method?: MatchMethod;\n tool?: { canonical_name: string; github_url: string; categories: string[] };\n }>;\n };\n if (!Array.isArray(body.resolved)) {\n warnings.push({\n scope: 'batch-resolve',\n message: 'batch-resolve returned unexpected body shape — falling back.',\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n\n const results: Array<{\n input: { name: string; ecosystem: Ecosystem };\n matched: boolean;\n match_method: MatchMethod;\n tool?: { canonical_name: string; github_url: string; categories: string[] };\n }> = [];\n for (const entry of body.resolved) {\n const method = entry.match_method ?? (entry.matched ? 'tool_name_exact' : 'none');\n const matched = entry.matched ?? method !== 'none';\n const key = `${entry.input.ecosystem}:${entry.input.name}`;\n methods.set(key, method);\n if (entry.tool?.github_url) githubUrls.set(key, entry.tool.github_url);\n results.push({ input: entry.input, matched, match_method: method, tool: entry.tool });\n }\n return { results, warnings, methods, githubUrls };\n } catch (err) {\n warnings.push({\n scope: 'batch-resolve',\n message: `batch-resolve network failure: ${err instanceof Error ? err.message : String(err)}. Tools classified as non_oss.`,\n });\n return {\n results: items.map((input) => ({ input, matched: false, match_method: 'none' })),\n warnings,\n methods,\n githubUrls,\n };\n }\n }\n\n // ── Feedback ─────────────────────────────────────────────────────────────\n\n async reportOutcome(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/feedback/outcome', args);\n }\n\n async suggestGraphUpdate(args: unknown): Promise<CallToolResult> {\n return this.post('/v1/feedback/suggest', args);\n }\n\n // ── Registration ─────────────────────────────────────────────────────────\n\n async register(clientId: string): Promise<{ ok: boolean; client_id: string }> {\n const res = await this.rawPost('/v1/register', { client_id: clientId });\n return res.json() as Promise<{ ok: boolean; client_id: string }>;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const res = await fetch(`${this.baseUrl}/v1/health`, {\n signal: AbortSignal.timeout(5_000),\n });\n return res.ok;\n } catch {\n return false;\n }\n }\n\n // ── Private ──────────────────────────────────────────────────────────────\n\n private async post(path: string, body: unknown): Promise<CallToolResult> {\n try {\n const res = await this.rawPost(path, body);\n const data = (await res.json()) as CallToolResult;\n\n // API returns a CallToolResult directly — pass it through\n if (data && typeof data === 'object' && 'content' in data) {\n return data;\n }\n\n // Unexpected response shape — wrap it\n return {\n content: [{ type: 'text', text: JSON.stringify(data) }],\n };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n ok: false,\n error: ErrorCode.ERR_NETWORK_UNREACHABLE,\n message: `ToolCairn API unreachable: ${msg}. Check your internet connection or try again later.`,\n }),\n },\n ],\n isError: true,\n };\n }\n }\n\n private rawPost(path: string, body: unknown): Promise<Response> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-ToolCairn-Key': this.apiKey,\n 'Accept-Encoding': 'gzip',\n };\n if (this.accessToken) {\n headers.Authorization = `Bearer ${this.accessToken}`;\n }\n return fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n }\n}\n","/**\n * Manages authentication credentials stored in ~/.toolcairn/credentials.json.\n * Authentication is required — there is no anonymous access.\n */\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CREDENTIALS_DIR = join(homedir(), '.toolcairn');\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\nconst PENDING_AUTH_FILE = join(CREDENTIALS_DIR, 'pending-auth.json');\n\nexport interface PendingAuth {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_at: string; // ISO timestamp\n api_url: string;\n}\n\nexport async function savePendingAuth(data: PendingAuth): Promise<void> {\n await mkdir(CREDENTIALS_DIR, { recursive: true });\n await writeFile(PENDING_AUTH_FILE, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport async function loadPendingAuth(): Promise<PendingAuth | null> {\n try {\n const raw = await readFile(PENDING_AUTH_FILE, 'utf-8');\n const data = JSON.parse(raw) as PendingAuth;\n if (new Date(data.expires_at) < new Date()) {\n await clearPendingAuth();\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\nexport async function clearPendingAuth(): Promise<void> {\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(PENDING_AUTH_FILE);\n } catch {\n // file didn't exist — that's fine\n }\n}\n\nexport interface Credentials {\n client_id: string;\n created_at: string;\n api_url?: string;\n access_token?: string;\n user_id?: string;\n user_email?: string;\n user_name?: string;\n authenticated_at?: string;\n}\n\n/**\n * Returns true if the credentials contain a valid, non-expired JWT access token.\n */\nexport function isTokenValid(creds: Credentials): boolean {\n if (!creds.access_token) return false;\n try {\n const parts = creds.access_token.split('.');\n if (parts.length !== 3) return false;\n // Decode payload without verifying signature — just check expiry client-side\n const payload = JSON.parse(Buffer.from(parts[1] ?? '', 'base64url').toString('utf-8')) as {\n exp?: number;\n };\n // Treat token as expired 5 min early to avoid race conditions\n if (payload.exp && payload.exp < Date.now() / 1000 + 300) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Load credentials from disk. Returns null if the file doesn't exist or has no valid token.\n */\nexport async function loadCredentials(): Promise<Credentials | null> {\n try {\n const raw = await readFile(CREDENTIALS_FILE, 'utf-8');\n return JSON.parse(raw) as Credentials;\n } catch {\n return null;\n }\n}\n\n/**\n * Load or create a minimal credentials stub (client_id only, no token).\n * Used as a placeholder before authentication completes.\n */\nexport async function loadOrCreateCredentials(): Promise<Credentials> {\n const existing = await loadCredentials();\n if (existing) return existing;\n\n const creds: Credentials = {\n client_id: crypto.randomUUID(),\n created_at: new Date().toISOString(),\n };\n await saveCredentials(creds);\n return creds;\n}\n\nexport async function saveCredentials(creds: Credentials): Promise<void> {\n await mkdir(CREDENTIALS_DIR, { recursive: true });\n await writeFile(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), 'utf-8');\n}\n\nexport async function getApiKey(): Promise<string> {\n const creds = await loadOrCreateCredentials();\n return creds.client_id;\n}\n\n/**\n * Merge authentication data into the existing credentials file.\n * Called after a successful device auth flow.\n */\nexport async function upgradeToAuthenticated(\n accessToken: string,\n apiKey: string,\n user: { id: string; email?: string | null; name?: string | null },\n): Promise<void> {\n const existing = await loadOrCreateCredentials();\n await saveCredentials({\n ...existing,\n client_id: apiKey,\n access_token: accessToken,\n user_id: user.id,\n user_email: user.email ?? undefined,\n user_name: user.name ?? undefined,\n authenticated_at: new Date().toISOString(),\n });\n}\n\n/**\n * Remove authentication data. Next startup will automatically trigger re-auth.\n */\nexport async function clearAuthentication(): Promise<void> {\n const existing = await loadOrCreateCredentials();\n await saveCredentials({\n client_id: existing.client_id,\n created_at: existing.created_at,\n api_url: existing.api_url,\n });\n}\n","/**\n * Device authorization flow for the MCP CLI.\n * Implements the OAuth 2.0 Device Authorization Grant (RFC 8628).\n *\n * Survives MCP process restarts: the device_code is written to\n * ~/.toolcairn/pending-auth.json immediately on first request.\n * On every subsequent startup, if this file exists and hasn't expired,\n * polling resumes automatically — no need to re-open the browser.\n */\nimport { AuthError, ErrorCode, NetworkError } from '@toolcairn/errors';\nimport {\n clearPendingAuth,\n loadPendingAuth,\n savePendingAuth,\n upgradeToAuthenticated,\n} from './credentials.js';\n\ninterface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n api_key: string;\n user: { id: string; email: string | null; name: string | null };\n error?: string;\n}\n\n/**\n * Open a URL in the default browser.\n * Uses spawn + detached so it works from stdio child processes (e.g. MCP server).\n * execSync blocks and fails silently in non-interactive contexts; spawn does not.\n */\nasync function openBrowser(url: string): Promise<void> {\n const { spawn } = await import('node:child_process');\n try {\n const platform = process.platform;\n let cmd: string;\n let args: string[];\n if (platform === 'win32') {\n cmd = 'cmd';\n args = ['/c', 'start', '', url];\n } else if (platform === 'darwin') {\n cmd = 'open';\n args = [url];\n } else {\n cmd = 'xdg-open';\n args = [url];\n }\n const child = spawn(cmd, args, { detached: true, stdio: 'ignore', shell: false });\n child.unref();\n } catch {\n // URL is printed to stderr as fallback\n }\n}\n\n/**\n * Request a new device code, persist it to ~/.toolcairn/pending-auth.json,\n * and open the browser automatically.\n *\n * Only call this on a FRESH start (no pending-auth.json). This is the only\n * place that opens the browser — the resume path in startDeviceAuth() never\n * opens the browser (prevents duplicate tabs on process restart).\n */\nexport async function requestDeviceCode(apiUrl: string): Promise<DeviceCodeResponse> {\n const res = await fetch(`${apiUrl}/v1/auth/device-code`, { method: 'POST' });\n if (!res.ok) {\n throw new NetworkError({\n code: ErrorCode.ERR_NETWORK_UNREACHABLE,\n message: 'Failed to start device auth. Check your internet connection.',\n });\n }\n const data = (await res.json()) as DeviceCodeResponse;\n\n // Persist immediately so polling can resume if this process is killed\n await savePendingAuth({\n device_code: data.device_code,\n user_code: data.user_code,\n verification_uri: data.verification_uri,\n expires_at: new Date(Date.now() + data.expires_in * 1000).toISOString(),\n api_url: apiUrl,\n });\n\n // Open browser here (fresh start only — resume path skips this)\n process.stderr.write('\\n──────────────────────────────────────────\\n');\n process.stderr.write(' ToolCairn — Sign In Required\\n');\n process.stderr.write('──────────────────────────────────────────\\n');\n process.stderr.write('\\n Opening browser for authentication...\\n\\n');\n process.stderr.write(` URL: ${data.verification_uri}\\n`);\n process.stderr.write(` Code: ${data.user_code}\\n\\n`);\n await openBrowser(data.verification_uri);\n\n return data;\n}\n\n/**\n * Start the full device auth flow — request code (or resume pending), open browser, poll.\n * Returns user info on success, throws on failure.\n *\n * On restart: if ~/.toolcairn/pending-auth.json exists and hasn't expired,\n * polling resumes for the same code (browser already opened, user might already\n * have confirmed — poll will return the token immediately).\n */\nexport async function startDeviceAuth(\n apiUrl: string,\n): Promise<{ userId: string; email: string; name: string | null }> {\n // Check for a pending auth from a previous (killed) process\n const pending = await loadPendingAuth();\n let codeData: DeviceCodeResponse;\n\n if (pending && pending.api_url === apiUrl) {\n // Resume from a previous (killed/restarted) process.\n // The browser was already opened — do NOT open it again (causes duplicate tabs).\n codeData = {\n device_code: pending.device_code,\n user_code: pending.user_code,\n verification_uri: pending.verification_uri,\n expires_in: Math.floor((new Date(pending.expires_at).getTime() - Date.now()) / 1000),\n interval: 5,\n };\n process.stderr.write('\\n ToolCairn: Waiting for sign-in confirmation...\\n');\n process.stderr.write(` URL: ${codeData.verification_uri}\\n`);\n process.stderr.write(` Code: ${codeData.user_code}\\n\\n`);\n // No openBrowser() call here — browser already open from previous session\n } else {\n // Fresh start — requestDeviceCode() opens the browser (only place that does)\n codeData = await requestDeviceCode(apiUrl);\n }\n\n const result = await pollForToken(apiUrl, codeData.device_code, 5);\n\n // Clear pending auth — successfully authenticated\n await clearPendingAuth();\n await upgradeToAuthenticated(result.access_token, result.api_key, result.user);\n\n process.stderr.write(`\\n ✓ Signed in as ${result.user.email}\\n\\n`);\n\n return {\n userId: result.user.id,\n email: result.user.email ?? '',\n name: result.user.name,\n };\n}\n\nasync function pollForToken(\n apiUrl: string,\n deviceCode: string,\n intervalSec: number,\n): Promise<TokenResponse> {\n const intervalMs = Math.max(intervalSec, 5) * 1000;\n\n while (true) {\n await sleep(intervalMs);\n\n const res = await fetch(`${apiUrl}/v1/auth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ device_code: deviceCode, grant_type: 'device_code' }),\n });\n\n const data = (await res.json()) as TokenResponse;\n\n if (data.error === 'authorization_pending') continue;\n if (data.error === 'expired_token') {\n await clearPendingAuth();\n throw new AuthError({\n code: ErrorCode.ERR_AUTH_TOKEN_EXPIRED,\n message: 'Device code expired. Please try again.',\n });\n }\n if (data.error) {\n throw new AuthError({\n code: ErrorCode.ERR_AUTH_UNAUTHORIZED,\n message: `Authorization failed: ${data.error}`,\n });\n }\n if (data.access_token) return data;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Project-level setup hooks — runs once at MCP server startup.\n *\n * As of v0.10.0 the MCP server NO LONGER auto-scaffolds `.toolcairn/config.json`\n * or `.toolcairn/events.jsonl`. Those files are owned by handler flows:\n * - `config.json` is created atomically by `mutateConfig` on the first call\n * that passes a `project_root` (cross-process locked, no race).\n * - `events.jsonl` is created on demand by the event-logger middleware when\n * `TOOLCAIRN_EVENTS_PATH` is set.\n *\n * What this module still does:\n * - Detects the host OS (for logging only).\n * - Writes `.toolcairn/tracker.html` — a read-only dashboard; safe to create at\n * startup because nothing else writes to it.\n *\n * The tracker's cwd placement is best-effort: `ensureProjectSetup` receives\n * `projectRoot` from the caller (the stdio server boot). If the agent later\n * invokes `toolcairn_init` with a different `project_root`, that handler bootstraps\n * config.json at the correct location via its own cross-process lock.\n */\n\nimport { access, mkdir, writeFile } from 'node:fs/promises';\nimport { platform, type } from 'node:os';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { generateTrackerHtml } from './tools/generate-tracker.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server:project-setup' });\n\n/**\n * Detect and return a human-readable OS label for logging.\n * Uses process.platform (win32 / darwin / linux / …).\n */\nfunction detectOs(): { platform: string; label: string } {\n const p = platform();\n const labels: Record<string, string> = {\n win32: 'Windows',\n darwin: 'macOS',\n linux: 'Linux',\n freebsd: 'FreeBSD',\n openbsd: 'OpenBSD',\n sunos: 'Solaris',\n android: 'Android',\n };\n return { platform: p, label: labels[p] ?? type() };\n}\n\n/**\n * Normalise an absolute file path to use forward slashes.\n * Required when embedding the path in a file:// URL inside tracker.html.\n * On Unix this is a no-op; on Windows it converts C:\\foo\\bar → C:/foo/bar.\n */\nfunction toFileUrl(absPath: string): string {\n return absPath.replace(/\\\\/g, '/');\n}\n\n/**\n * Ensure `.toolcairn/tracker.html` exists in `projectRoot`. No-op if already present.\n * Does NOT write `config.json` or `events.jsonl` — handlers own those.\n */\nexport async function ensureProjectSetup(projectRoot = process.cwd()): Promise<void> {\n const os = detectOs();\n logger.info(\n { os: os.label, platform: os.platform, projectRoot },\n 'Detected OS — starting project setup',\n );\n\n const dir = join(projectRoot, '.toolcairn');\n const trackerPath = join(dir, 'tracker.html');\n const eventsPathAbs = join(dir, 'events.jsonl');\n\n // tracker.html embeds the events path in a file:// URL — must use forward slashes\n const eventsPathForUrl = toFileUrl(eventsPathAbs);\n\n try {\n await mkdir(dir, { recursive: true });\n await createIfAbsent(trackerPath, generateTrackerHtml(eventsPathForUrl), 'tracker.html');\n logger.info({ dir, os: os.label }, '.toolcairn tracker ready');\n } catch (e) {\n // Non-fatal — server still starts even if setup fails (read-only fs, perms, etc.)\n logger.warn(\n { err: e, dir, os: os.label },\n 'tracker.html setup failed — continuing (config.json still bootstrapped by handlers)',\n );\n }\n}\n\nasync function createIfAbsent(filePath: string, content: string, label: string): Promise<void> {\n try {\n await access(filePath);\n logger.debug({ file: label }, 'Already exists — skipping');\n } catch {\n await writeFile(filePath, content, 'utf-8');\n logger.info({ file: label }, 'Created');\n }\n}\n","/**\n * Generate the standalone tracker.html content.\n * Called by toolcairn_init to produce the HTML file content.\n * The agent writes the returned content to .toolcairn/tracker.html\n */\nexport function generateTrackerHtml(eventsPath: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n<title>ToolCairn Tracker</title>\n<style>\n :root {\n --bg: #0a0a0f;\n --surface: #12121a;\n --surface2: #1a1a26;\n --border: #2a2a3a;\n --accent: #7c5cfc;\n --accent2: #5b8def;\n --green: #22c55e;\n --red: #ef4444;\n --yellow: #f59e0b;\n --text: #e2e8f0;\n --muted: #64748b;\n --mono: 'JetBrains Mono', 'Fira Code', monospace;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { background: var(--bg); color: var(--text); font-family: system-ui, sans-serif; font-size: 14px; min-height: 100vh; }\n\n header { display: flex; align-items: center; gap: 12px; padding: 16px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }\n header h1 { font-size: 16px; font-weight: 700; letter-spacing: -0.02em; }\n header h1 span { color: var(--accent); }\n .status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); animation: pulse 2s infinite; margin-left: auto; }\n .status-dot.paused { background: var(--yellow); animation: none; }\n @keyframes pulse { 0%,100%{ opacity:1; } 50%{ opacity:0.4; } }\n\n .controls { display: flex; gap: 8px; align-items: center; padding: 12px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }\n .btn { padding: 5px 12px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface2); color: var(--text); cursor: pointer; font-size: 12px; transition: border-color .15s; }\n .btn:hover { border-color: var(--accent); }\n .btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }\n input[type=range] { accent-color: var(--accent); }\n .label { color: var(--muted); font-size: 12px; }\n\n .metrics { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 1px; background: var(--border); border-bottom: 1px solid var(--border); }\n .metric { background: var(--surface); padding: 14px 18px; }\n .metric-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px; }\n .metric-value { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }\n .metric-value.green { color: var(--green); }\n .metric-value.red { color: var(--red); }\n .metric-value.accent { color: var(--accent); }\n .metric-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }\n\n .layout { display: grid; grid-template-columns: 1fr 340px; height: calc(100vh - 140px); }\n .feed { overflow-y: auto; border-right: 1px solid var(--border); }\n .sidebar { overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; }\n\n .event-row { display: grid; grid-template-columns: 80px 160px 1fr auto auto; gap: 12px; align-items: center; padding: 8px 16px; border-bottom: 1px solid #1a1a22; transition: background .1s; cursor: pointer; }\n .event-row:hover { background: var(--surface2); }\n .event-row.selected { background: #1e1a30; }\n .event-row .time { font-family: var(--mono); font-size: 11px; color: var(--muted); }\n .event-row .tool { font-family: var(--mono); font-size: 12px; color: var(--accent); font-weight: 600; }\n .event-row .summary { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .event-row .dur { font-family: var(--mono); font-size: 11px; color: var(--muted); text-align: right; }\n .badge { display: inline-flex; align-items: center; padding: 2px 7px; border-radius: 4px; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }\n .badge.ok { background: rgba(34,197,94,.15); color: var(--green); }\n .badge.error { background: rgba(239,68,68,.15); color: var(--red); }\n .badge.warn { background: rgba(245,158,11,.15); color: var(--yellow); }\n\n .detail-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 14px; }\n .detail-card h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 10px; }\n .kv { display: flex; justify-content: space-between; padding: 3px 0; border-bottom: 1px solid #1a1a22; font-size: 12px; }\n .kv:last-child { border-bottom: none; }\n .kv .k { color: var(--muted); }\n .kv .v { font-family: var(--mono); color: var(--text); }\n .kv .v.green { color: var(--green); }\n .kv .v.red { color: var(--red); }\n .kv .v.yellow { color: var(--yellow); }\n\n .bar-chart { margin-top: 6px; }\n .bar-row { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; font-size: 11px; }\n .bar-label { width: 120px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: right; }\n .bar-track { flex: 1; height: 6px; background: var(--surface2); border-radius: 3px; }\n .bar-fill { height: 100%; border-radius: 3px; background: var(--accent); transition: width .3s; }\n .bar-count { width: 28px; text-align: right; color: var(--text); }\n\n .empty { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--muted); gap: 8px; }\n .empty svg { opacity: .3; }\n .empty p { font-size: 13px; }\n .empty code { font-family: var(--mono); font-size: 11px; background: var(--surface2); padding: 3px 8px; border-radius: 4px; color: var(--accent); }\n\n .insights-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }\n .insight-item { background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; font-size: 12px; }\n .insight-item .i-tool { color: var(--accent); font-family: var(--mono); font-weight: 600; }\n .insight-item .i-text { color: var(--muted); margin-top: 2px; }\n\n ::-webkit-scrollbar { width: 4px; }\n ::-webkit-scrollbar-track { background: transparent; }\n ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }\n</style>\n</head>\n<body>\n\n<header>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <circle cx=\"10\" cy=\"10\" r=\"9\" stroke=\"#7c5cfc\" stroke-width=\"1.5\"/>\n <path d=\"M6 10h8M10 6v8\" stroke=\"#7c5cfc\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <h1><span>Tool</span>Pilot Tracker</h1>\n <div id=\"statusText\" style=\"font-size:12px; color:var(--muted);\">Loading...</div>\n <div id=\"statusDot\" class=\"status-dot paused\"></div>\n</header>\n\n<div class=\"controls\">\n <button class=\"btn active\" id=\"btnLive\" onclick=\"toggleLive()\">⬤ Live</button>\n <button class=\"btn\" id=\"btnClear\" onclick=\"clearEvents()\">Clear</button>\n <span class=\"label\" style=\"margin-left:8px;\">Interval:</span>\n <input type=\"range\" min=\"1\" max=\"30\" value=\"3\" id=\"intervalSlider\" onchange=\"setInterval_(this.value)\" style=\"width:80px;\" />\n <span class=\"label\" id=\"intervalLabel\">3s</span>\n <span style=\"margin-left:auto; font-size:11px; color:var(--muted);\" id=\"lastRefresh\">—</span>\n</div>\n\n<div class=\"metrics\" id=\"metrics\">\n <div class=\"metric\"><div class=\"metric-label\">Total Calls</div><div class=\"metric-value accent\" id=\"mTotal\">0</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Success Rate</div><div class=\"metric-value green\" id=\"mSuccess\">—</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Avg Latency</div><div class=\"metric-value\" id=\"mLatency\">—</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Issues Caught</div><div class=\"metric-value yellow\" id=\"mIssues\">0</div><div class=\"metric-sub\">check_issue calls</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Deprecation Warns</div><div class=\"metric-value yellow\" id=\"mDeprecation\">0</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Non-OSS Guided</div><div class=\"metric-value\" id=\"mNonOss\">0</div></div>\n <div class=\"metric\"><div class=\"metric-label\">Graph Updates</div><div class=\"metric-value accent\" id=\"mGraph\">0</div></div>\n</div>\n\n<div class=\"layout\">\n <div class=\"feed\" id=\"feed\">\n <div class=\"empty\" id=\"emptyState\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\"><circle cx=\"20\" cy=\"20\" r=\"18\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\"/><path d=\"M13 20h14M20 13v14\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>\n <p>Waiting for MCP tool calls...</p>\n <code>Set TOOLCAIRN_EVENTS_PATH in your MCP server env</code>\n </div>\n </div>\n <div class=\"sidebar\">\n <div class=\"detail-card\" id=\"detailPanel\" style=\"display:none\">\n <h3>Event Detail</h3>\n <div id=\"detailContent\"></div>\n </div>\n <div class=\"detail-card\">\n <h3>Calls by Tool</h3>\n <div id=\"toolChart\" class=\"bar-chart\"></div>\n </div>\n <div class=\"detail-card\">\n <h3>Recent Insights</h3>\n <ul class=\"insights-list\" id=\"insightsList\"></ul>\n </div>\n </div>\n</div>\n\n<script>\n// ─── Config ──────────────────────────────────────────────────────────────────\nconst EVENTS_PATH = ${JSON.stringify(eventsPath)};\n\n// ─── State ───────────────────────────────────────────────────────────────────\nlet allEvents = [];\nlet selectedId = null;\nlet isLive = true;\nlet pollIntervalMs = 3000;\nlet pollHandle = null;\nlet lastByteOffset = 0;\n\n// ─── Polling ──────────────────────────────────────────────────────────────────\nasync function fetchEvents() {\n if (!EVENTS_PATH) return;\n try {\n // Fetch with range header to only get new bytes\n const headers = lastByteOffset > 0 ? { 'Range': \\`bytes=\\${lastByteOffset}-\\` } : {};\n const res = await fetch(\\`file://\\${EVENTS_PATH}\\`, { headers }).catch(() => null);\n if (!res) return;\n\n const text = await res.text();\n if (!text.trim()) return;\n\n const newLines = text.trim().split('\\\\n').filter(Boolean);\n let added = 0;\n for (const line of newLines) {\n try {\n const ev = JSON.parse(line);\n if (!allEvents.find(e => e.id === ev.id)) {\n allEvents.push(ev);\n added++;\n }\n } catch {}\n }\n\n if (added > 0) {\n allEvents.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));\n renderAll();\n }\n\n document.getElementById('lastRefresh').textContent = 'Updated ' + new Date().toLocaleTimeString();\n document.getElementById('statusDot').className = 'status-dot' + (isLive ? '' : ' paused');\n document.getElementById('statusText').textContent = \\`\\${allEvents.length} events\\`;\n } catch (e) {\n console.warn('Fetch error', e);\n }\n}\n\nfunction toggleLive() {\n isLive = !isLive;\n document.getElementById('btnLive').className = 'btn' + (isLive ? ' active' : '');\n document.getElementById('statusDot').className = 'status-dot' + (isLive ? '' : ' paused');\n if (isLive) startPolling(); else stopPolling();\n}\n\nfunction clearEvents() {\n allEvents = [];\n selectedId = null;\n renderAll();\n}\n\nfunction setInterval_(v) {\n pollIntervalMs = Number(v) * 1000;\n document.getElementById('intervalLabel').textContent = v + 's';\n if (isLive) { stopPolling(); startPolling(); }\n}\n\nfunction startPolling() {\n if (pollHandle) clearInterval(pollHandle);\n fetchEvents();\n pollHandle = setInterval(fetchEvents, pollIntervalMs);\n}\n\nfunction stopPolling() {\n if (pollHandle) { clearInterval(pollHandle); pollHandle = null; }\n}\n\n// ─── Render ───────────────────────────────────────────────────────────────────\nfunction fmtTime(iso) {\n return new Date(iso).toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nfunction toolSummary(ev) {\n const m = ev.metadata || {};\n if (ev.tool_name === 'search_tools' || ev.tool_name === 'search_tools_respond') {\n const parts = [];\n if (m.is_two_option) parts.push('2-option result');\n if (m.had_non_indexed_guidance) parts.push('non-OSS guidance');\n if (m.had_deprecation_warning) parts.push('⚠ deprecated tool');\n if (m.had_credibility_warning) parts.push('⚠ low-stars warning');\n return parts.join(' · ') || m.status || '';\n }\n if (ev.tool_name === 'check_issue') return m.status ? \\`status: \\${m.status}\\` : '';\n if (ev.tool_name === 'suggest_graph_update') {\n if (m.auto_graduated) return '✓ auto-graduated to graph';\n if (m.staged) return 'staged for review';\n return '';\n }\n if (ev.tool_name === 'compare_tools') return m.recommendation ? \\`rec: \\${m.recommendation}\\` : '';\n if (ev.tool_name === 'check_compatibility') return m.compatibility_signal ? m.compatibility_signal : '';\n return m.status || '';\n}\n\nfunction renderFeed() {\n const feed = document.getElementById('feed');\n const empty = document.getElementById('emptyState');\n if (allEvents.length === 0) {\n empty.style.display = 'flex';\n feed.querySelectorAll('.event-row').forEach(r => r.remove());\n return;\n }\n empty.style.display = 'none';\n\n // Remove rows not in allEvents\n const existingIds = new Set(Array.from(feed.querySelectorAll('.event-row')).map(r => r.dataset.id));\n const currentIds = new Set(allEvents.map(e => e.id));\n existingIds.forEach(id => { if (!currentIds.has(id)) feed.querySelector(\\`[data-id=\"\\${id}\"]\\`)?.remove(); });\n\n // Add new rows at top\n for (const ev of allEvents) {\n if (feed.querySelector(\\`[data-id=\"\\${ev.id}\"]\\`)) continue;\n const row = document.createElement('div');\n row.className = 'event-row' + (selectedId === ev.id ? ' selected' : '');\n row.dataset.id = ev.id;\n row.onclick = () => selectEvent(ev.id);\n\n const badgeClass = ev.status === 'ok' ? 'ok' : 'error';\n const summary = toolSummary(ev);\n row.innerHTML = \\`\n <span class=\"time\">\\${fmtTime(ev.created_at)}</span>\n <span class=\"tool\">\\${ev.tool_name}</span>\n <span class=\"summary\">\\${summary}</span>\n <span class=\"dur\">\\${ev.duration_ms}ms</span>\n <span class=\"badge \\${badgeClass}\">\\${ev.status}</span>\n \\`;\n\n // Insert in chronological order (newest first)\n const firstRow = feed.querySelector('.event-row');\n if (firstRow) feed.insertBefore(row, firstRow);\n else feed.appendChild(row);\n }\n}\n\nfunction renderMetrics() {\n const total = allEvents.length;\n const okCount = allEvents.filter(e => e.status === 'ok').length;\n const avgMs = total > 0 ? Math.round(allEvents.reduce((s, e) => s + e.duration_ms, 0) / total) : 0;\n const issueCount = allEvents.filter(e => e.tool_name === 'check_issue').length;\n const deprecCount = allEvents.filter(e => e.metadata?.had_deprecation_warning).length;\n const nonOssCount = allEvents.filter(e => e.metadata?.had_non_indexed_guidance).length;\n const graphCount = allEvents.filter(e => e.tool_name === 'suggest_graph_update').length;\n\n document.getElementById('mTotal').textContent = total;\n document.getElementById('mSuccess').textContent = total > 0 ? Math.round(okCount / total * 100) + '%' : '—';\n document.getElementById('mLatency').textContent = total > 0 ? avgMs + 'ms' : '—';\n document.getElementById('mIssues').textContent = issueCount;\n document.getElementById('mDeprecation').textContent = deprecCount;\n document.getElementById('mNonOss').textContent = nonOssCount;\n document.getElementById('mGraph').textContent = graphCount;\n}\n\nfunction renderToolChart() {\n const counts = {};\n for (const ev of allEvents) counts[ev.tool_name] = (counts[ev.tool_name] || 0) + 1;\n const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, 8);\n const max = sorted[0]?.[1] || 1;\n const html = sorted.map(([tool, count]) => \\`\n <div class=\"bar-row\">\n <span class=\"bar-label\">\\${tool}</span>\n <div class=\"bar-track\"><div class=\"bar-fill\" style=\"width:\\${count/max*100}%\"></div></div>\n <span class=\"bar-count\">\\${count}</span>\n </div>\n \\`).join('');\n document.getElementById('toolChart').innerHTML = html || '<span style=\"color:var(--muted);font-size:12px\">No data yet</span>';\n}\n\nfunction renderInsights() {\n const insights = [];\n for (const ev of allEvents.slice(0, 50)) {\n const m = ev.metadata || {};\n if (ev.tool_name === 'check_issue' && ev.status === 'ok') {\n insights.push({ tool: ev.tool_name, text: 'Issue check ran — may have prevented a debug loop', time: ev.created_at });\n }\n if (m.had_deprecation_warning) {\n insights.push({ tool: ev.tool_name, text: 'Deprecated/unmaintained tool detected in results', time: ev.created_at });\n }\n if (m.auto_graduated) {\n insights.push({ tool: 'suggest_graph_update', text: 'New edge auto-graduated to graph (confidence ≥0.8)', time: ev.created_at });\n }\n if (m.had_non_indexed_guidance) {\n insights.push({ tool: ev.tool_name, text: 'Non-indexed tool detected — non-OSS guidance provided', time: ev.created_at });\n }\n if (m.recommendation) {\n insights.push({ tool: 'compare_tools', text: \\`Tool comparison recommended: \\${m.recommendation}\\`, time: ev.created_at });\n }\n }\n const list = document.getElementById('insightsList');\n if (insights.length === 0) {\n list.innerHTML = '<li style=\"color:var(--muted);font-size:12px\">No insights yet</li>';\n return;\n }\n list.innerHTML = insights.slice(0, 8).map(i => \\`\n <li class=\"insight-item\">\n <div class=\"i-tool\">\\${i.tool}</div>\n <div class=\"i-text\">\\${i.text}</div>\n </li>\n \\`).join('');\n}\n\nfunction selectEvent(id) {\n selectedId = id;\n document.querySelectorAll('.event-row').forEach(r => r.classList.toggle('selected', r.dataset.id === id));\n const ev = allEvents.find(e => e.id === id);\n if (!ev) return;\n const panel = document.getElementById('detailPanel');\n const content = document.getElementById('detailContent');\n panel.style.display = 'block';\n const m = ev.metadata || {};\n const rows = [\n ['Tool', ev.tool_name],\n ['Status', ev.status],\n ['Duration', ev.duration_ms + 'ms'],\n ['Time', new Date(ev.created_at).toLocaleString()],\n ev.query_id ? ['Session ID', ev.query_id.slice(0, 8) + '...'] : null,\n ...Object.entries(m).filter(([k]) => k !== 'tool').map(([k, v]) => [k, String(v)])\n ].filter(Boolean);\n content.innerHTML = rows.map(([k, v]) => {\n const cls = v === 'true' || v === 'ok' ? 'green' : v === 'false' || v === 'error' ? 'red' : '';\n return \\`<div class=\"kv\"><span class=\"k\">\\${k}</span><span class=\"v \\${cls}\">\\${v}</span></div>\\`;\n }).join('');\n}\n\nfunction renderAll() {\n renderFeed();\n renderMetrics();\n renderToolChart();\n renderInsights();\n}\n\n// ─── Boot ─────────────────────────────────────────────────────────────────────\nif (!EVENTS_PATH || EVENTS_PATH === 'null') {\n document.getElementById('statusText').textContent = 'No events path configured';\n document.getElementById('emptyState').querySelector('p').textContent = 'TOOLCAIRN_EVENTS_PATH not set in MCP server environment';\n} else {\n startPolling();\n}\n</script>\n</body>\n</html>`;\n}\n","/**\n * Production MCP server — thin HTTP bridge.\n *\n * LOCAL tools (classify_prompt, *_config, toolcairn_init) run directly.\n * All other tools make a single HTTP call to the ToolCairn API via ToolCairnClient.\n *\n * This file is used when TOOLPILOT_MODE=production (npx @toolcairn/mcp).\n * It intentionally imports NOTHING from @toolcairn/graph, @toolcairn/search,\n * @toolcairn/vector, @toolcairn/db, or @toolcairn/queue so those packages\n * are not bundled into the published npm package.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { config } from '@toolcairn/config';\nimport { createMcpLogger, withErrorHandling } from '@toolcairn/errors';\nimport {\n ToolCairnClient,\n clearAuthentication,\n isTokenValid,\n loadCredentials,\n startDeviceAuth,\n} from '@toolcairn/remote';\n// Use the /local subpath — excludes heavy DB/search/graph deps from the npm bundle.\n// The full '@toolcairn/tools' CJS dist requires Prisma/neo4j/ioredis at load time\n// even though prod mode never calls those code paths.\nimport {\n checkCompatibilitySchema,\n checkIssueSchema,\n classifyPromptSchema,\n compareToolsSchema,\n getStackSchema,\n handleClassifyPrompt,\n handleReadProjectConfig,\n handleToolcairnInit,\n handleUpdateProjectConfig,\n readProjectConfigSchema,\n refineRequirementSchema,\n reportOutcomeSchema,\n searchToolsRespondSchema,\n searchToolsSchema,\n suggestGraphUpdateSchema,\n toolcairnInitSchema,\n updateProjectConfigSchema,\n verifySuggestionSchema,\n} from '@toolcairn/tools-local';\nimport { z } from 'zod';\nimport { withEventLogging } from './middleware/event-logger.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server:prod' });\n\nconst SETUP_INSTRUCTIONS = `\n# ToolCairn — Agent Setup Instructions\n\nYou are connected to the ToolCairn MCP server. ToolCairn is your active tool intelligence co-pilot.\n\n## The Server Owns .toolcairn/ (v0.10.0+)\n\nThe MCP server reads and writes \\`.toolcairn/config.json\\` + \\`.toolcairn/audit-log.jsonl\\`\natomically under a cross-process lock. You never touch those files directly.\n\n## On Every Session Start — Do This First\n\nCall \\`read_project_config\\` with \\`project_root\\` (absolute path to the user's project).\n- If it returns \\`status: \"not_initialized\"\\`: the project has no config yet. Call\n \\`toolcairn_init\\` with \\`agent\\` (your type) + \\`project_root\\`. The server walks\n every workspace, parses manifests across 12 ecosystems, classifies tools against\n the ToolCairn graph, and atomically writes \\`.toolcairn/config.json\\`.\n After that, apply the returned \\`setup_steps\\` (append rules to CLAUDE.md,\n merge the toolcairn entry into .mcp.json, update .gitignore).\n- If it returns \\`status: \"ready\"\\`: you have the full project snapshot. Review\n \\`stale_tools\\` / \\`pending_tools\\` and proceed with work.\n\n## Applying Mutations\n\nWhen the user selects / replaces / drops a tool, call \\`update_project_config\\`\nwith \\`project_root\\`, \\`action\\` (add_tool / remove_tool / update_tool / add_evaluation),\nand \\`tool_name\\`. The server:\n- atomically updates \\`.toolcairn/config.json\\`,\n- appends a new line to \\`.toolcairn/audit-log.jsonl\\` (FIFO-archived at 1000 entries),\n- returns the new \\`last_audit_entry\\` for your record.\n\nDo NOT construct or write these files yourself — you do not have the cross-process\nlock that protects them.\n\n## Schema Migration\n\nConfigs written by v0.9.x are on schema 1.0. The first \\`read_project_config\\` or\n\\`update_project_config\\` call after upgrade migrates in place to 1.1 (languages →\narray, frameworks → array, \\`audit_log[]\\` relocated from config.json to\naudit-log.jsonl). The migration is logged as an audit entry.\n\n## When to Use ToolCairn Tools\n\n| Situation | Tool to call |\n|-----------|-------------|\n| User asks which tool to use for X | \\`classify_prompt\\` → \\`refine_requirement\\` → \\`search_tools\\` |\n| User needs to compare two tools | \\`compare_tools\\` |\n| User asks if tool A works with tool B | \\`check_compatibility\\` |\n| Error persists after 4+ retries AND docs checked | \\`check_issue\\` |\n| User asks for a recommended stack | \\`get_stack\\` |\n| search_tools returns empty or low confidence | \\`verify_suggestion\\` |\n| You discover a new tool relationship | \\`suggest_graph_update\\` |\n| A tool worked well or was replaced | \\`report_outcome\\` |\n| Tool added/removed from project | \\`update_project_config\\` |\n`.trim();\n\n/**\n * Register all 14 production tools (local + remote) on an existing McpServer.\n * Called either during buildProdServer() or dynamically after auth completes\n * on the waiting server — the MCP SDK notifies the client via\n * notifications/tools/list_changed so tools appear without reconnect.\n */\nexport async function addToolsToServer(server: McpServer): Promise<void> {\n const creds = await loadCredentials();\n if (!creds || !isTokenValid(creds)) {\n throw new Error('ToolCairn: authentication required.');\n }\n\n const remote = new ToolCairnClient({\n baseUrl: config.TOOLPILOT_API_URL,\n apiKey: creds.client_id,\n accessToken: creds.access_token,\n });\n\n logger.info({ user: creds.user_email }, 'Registering production tools');\n\n /**\n * Composes event logging + error handling around a tool handler.\n * Execution order: withEventLogging → withErrorHandling → handler\n * This ensures events are always recorded even when errors occur.\n *\n * Uses Record<string, unknown> at the composition boundary — individual\n * handlers still receive the validated args from their own Zod schemas.\n */\n type AnyHandler = (\n args: Record<string, unknown>,\n ) => Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>;\n function wrap(toolName: string, fn: AnyHandler) {\n return withEventLogging(toolName, withErrorHandling(toolName, logger, fn));\n }\n\n // ── LOCAL tools (zero network, run on user's machine) ──────────────────────\n\n server.registerTool(\n 'classify_prompt',\n {\n description:\n 'Classify a developer prompt to determine if ToolCairn tool search is needed. Returns a structured classification prompt for the agent to evaluate.',\n inputSchema: classifyPromptSchema,\n },\n wrap('classify_prompt', async (args) =>\n handleClassifyPrompt(args as Parameters<typeof handleClassifyPrompt>[0]),\n ),\n );\n\n server.registerTool(\n 'toolcairn_init',\n {\n description:\n 'Bootstrap ToolCairn for the current project. Walks every workspace, parses manifests across 12 ecosystems, classifies tools against the ToolCairn graph, and writes .toolcairn/config.json + audit-log.jsonl atomically. Returns setup_steps for CLAUDE.md / .mcp.json / .gitignore (agent applies those).',\n inputSchema: toolcairnInitSchema,\n },\n wrap('toolcairn_init', async (args) =>\n handleToolcairnInit(args as Parameters<typeof handleToolcairnInit>[0], {\n batchResolve: (items) => remote.batchResolve(items),\n }),\n ),\n );\n\n server.registerTool(\n 'read_project_config',\n {\n description:\n 'Read .toolcairn/config.json from disk and return the structured project snapshot: project metadata, confirmed tools, stale tools, pending evaluations, and last audit entry. Auto-migrates v1.0 configs to v1.1 on first read.',\n inputSchema: readProjectConfigSchema,\n },\n wrap('read_project_config', async (args) =>\n handleReadProjectConfig(args as Parameters<typeof handleReadProjectConfig>[0]),\n ),\n );\n\n server.registerTool(\n 'update_project_config',\n {\n description:\n 'Apply a mutation to .toolcairn/config.json (add_tool / remove_tool / update_tool / add_evaluation). The server atomically rewrites config.json and appends a new line to audit-log.jsonl under a cross-process lock. Requires project_root.',\n inputSchema: updateProjectConfigSchema,\n },\n wrap('update_project_config', async (args) =>\n handleUpdateProjectConfig(args as Parameters<typeof handleUpdateProjectConfig>[0]),\n ),\n );\n\n // ── REMOTE tools (one HTTP call each to ToolCairn API) ────────────────────\n\n server.registerTool(\n 'search_tools',\n {\n description:\n 'Search for the best tool for a specific need using a natural language query. Initiates a guided discovery session with clarification questions when needed.',\n inputSchema: searchToolsSchema,\n },\n wrap('search_tools', async (args) => remote.searchTools(args)),\n );\n\n server.registerTool(\n 'search_tools_respond',\n {\n description:\n 'Submit clarification answers for an in-progress tool search session and receive refined results.',\n inputSchema: searchToolsRespondSchema,\n },\n wrap('search_tools_respond', async (args) => remote.searchToolsRespond(args)),\n );\n\n server.registerTool(\n 'get_stack',\n {\n description:\n 'Build a complementary tool stack for a project use case. For best results, call refine_requirement first with classification \"stack_building\", evaluate its decomposition_prompt to get sub-needs, then pass each {sub_need_type, keyword_sentence} object as a sub_needs entry. This lets get_stack keyword-match per layer (e.g. \"web-framework\", \"database\", \"auth\") instead of one broad search. Falls back to balanced search when sub_needs is omitted. Each tool in the returned stack also carries a `version` object with the recommended version that is cross-compatible with the rest of the stack (downgraded from latest if needed to satisfy peer constraints), plus a top-level `compatibility_matrix` + `stack_compatibility` summarising cross-tool version fit.',\n inputSchema: getStackSchema,\n },\n wrap('get_stack', async (args) => remote.getStack(args)),\n );\n\n server.registerTool(\n 'check_compatibility',\n {\n description:\n 'Check compatibility between two tools with version-aware matching. When both tools have declared dependency metadata (npm peerDependencies, PyPI requires_dist, etc.) the handler evaluates range constraints directly and returns a version_checks array plus runtime_requirements. Pass optional tool_a_version / tool_b_version to evaluate specific versions (e.g. \"is next@14 compatible with react@17?\"). Falls back to graph-edge + shared-neighbors inference when version metadata is unavailable. Response includes `source`: \"declared_dependency\" | \"graph_edges\" | \"shared_neighbors\".',\n inputSchema: checkCompatibilitySchema,\n },\n wrap('check_compatibility', async (args) => remote.checkCompatibility(args)),\n );\n\n server.registerTool(\n 'compare_tools',\n {\n description:\n 'Compare two tools head-to-head using health signals, graph relationships, and community data.',\n inputSchema: compareToolsSchema,\n },\n wrap('compare_tools', async (args) => remote.compareTools(args)),\n );\n\n server.registerTool(\n 'refine_requirement',\n {\n description: 'Decompose a vague user use-case into specific, searchable tool requirements.',\n inputSchema: refineRequirementSchema,\n },\n wrap('refine_requirement', async (args) => remote.refineRequirement(args)),\n );\n\n server.registerTool(\n 'check_issue',\n {\n description:\n 'LAST RESORT — check GitHub Issues for a known error after 4+ retries and docs review.',\n inputSchema: checkIssueSchema,\n },\n wrap('check_issue', async (args) => remote.checkIssue(args)),\n );\n\n server.registerTool(\n 'verify_suggestion',\n {\n description: 'Validate agent-suggested tools against the ToolCairn graph.',\n inputSchema: verifySuggestionSchema,\n },\n wrap('verify_suggestion', async (args) => remote.verifySuggestion(args)),\n );\n\n server.registerTool(\n 'report_outcome',\n {\n description: 'Report the outcome of using a tool recommended by ToolCairn (fire-and-forget).',\n inputSchema: reportOutcomeSchema,\n },\n wrap('report_outcome', async (args) => remote.reportOutcome(args)),\n );\n\n server.registerTool(\n 'suggest_graph_update',\n {\n description:\n 'Suggest a new tool, relationship, use case, or health update to the ToolCairn graph.',\n inputSchema: suggestGraphUpdateSchema,\n },\n wrap('suggest_graph_update', async (args) => remote.suggestGraphUpdate(args)),\n );\n\n // ── AUTH tool (local — manages ~/.toolcairn/credentials.json) ─────────────\n\n server.registerTool(\n 'toolcairn_auth',\n {\n description:\n 'Manage your ToolCairn authentication. Use \"login\" to authenticate via browser (unlocks higher rate limits), \"status\" to check current auth state, or \"logout\" to revert to anonymous mode.',\n inputSchema: z.object({\n action: z\n .enum(['login', 'status', 'logout'])\n .describe(\n '\"login\" opens a browser to authenticate, \"status\" shows current auth state, \"logout\" clears authentication',\n ),\n }),\n },\n async ({ action }) => {\n if (action === 'status') {\n const c = await loadCredentials();\n const isAuth = c !== null && isTokenValid(c);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n authenticated: isAuth,\n user_email: c?.user_email ?? null,\n user_name: c?.user_name ?? null,\n authenticated_at: c?.authenticated_at ?? null,\n }),\n },\n ],\n };\n }\n\n if (action === 'logout') {\n await clearAuthentication();\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n ok: true,\n message:\n 'Signed out. Restart your agent to sign in again — authentication will start automatically.',\n }),\n },\n ],\n };\n }\n\n // action === 'login'\n try {\n const user = await startDeviceAuth(config.TOOLPILOT_API_URL);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n ok: true,\n message: `Successfully authenticated as ${user.email}. All tools are now authorized.`,\n user_email: user.email,\n user_name: user.name,\n }),\n },\n ],\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Authentication failed';\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ ok: false, error: msg }) }],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Build a new fully-authenticated prod server.\n * Creates the McpServer then delegates tool registration to addToolsToServer().\n */\nexport async function buildProdServer(): Promise<McpServer> {\n const server = new McpServer(\n { name: 'toolcairn', version: '0.1.0' },\n { instructions: SETUP_INSTRUCTIONS },\n );\n await addToolsToServer(server);\n return server;\n}\n","/**\n * @toolcairn/tools-local\n *\n * Production-safe handlers and schemas — zero DB/search/graph dependencies.\n * Used by the published MCP server bundle (npx @neurynae/toolcairn-mcp).\n *\n * Local handlers run entirely on the user's machine.\n * Remote tool schemas are re-exported here for MCP tool registration.\n */\n\n// Zod input schemas (all tools — needed for MCP tool registration in prod server)\nexport * from './schemas.js';\n\n// Type utilities\nexport { okResult, errResult } from './utils.js';\nexport type { FormattedResult } from './format-results.js';\n\n// Local handlers — run entirely on the user's machine, zero DB deps\nexport { handleClassifyPrompt } from './handlers/classify-prompt.js';\nexport {\n handleToolcairnInit,\n type HandleToolcairnInitDeps,\n} from './handlers/toolcairn-init.js';\nexport { handleReadProjectConfig } from './handlers/read-project-config.js';\nexport { handleUpdateProjectConfig } from './handlers/update-project-config.js';\n\n// Discovery + config-store — exported for local E2E / direct embedding\nexport * from './discovery/index.js';\nexport {\n mutateConfig,\n readConfig,\n writeConfig,\n appendAudit,\n bulkAppendAudit,\n readLiveAudit,\n migrateToV1_1,\n emptySkeleton,\n joinConfigPath,\n joinAuditPath,\n joinConfigDir,\n CONFIG_DIR,\n CONFIG_FILE,\n AUDIT_LOG_FILE,\n AUDIT_ARCHIVE_FILE,\n type Mutator,\n type MutateResult,\n type PendingAuditEntry,\n type MigrateResult,\n type ReadConfigResult,\n} from './config-store/index.js';\n","import { z } from 'zod';\n\nexport const searchToolsSchema = {\n query: z.string().min(1).max(500),\n context: z.object({ filters: z.record(z.string(), z.unknown()) }).optional(),\n query_id: z.string().uuid().optional(),\n user_id: z.string().optional(),\n};\n\nexport const searchToolsRespondSchema = {\n query_id: z.string().uuid(),\n answers: z.array(z.object({ dimension: z.string(), value: z.string() })),\n};\n\nexport const reportOutcomeSchema = {\n query_id: z.string().uuid(),\n chosen_tool: z.string(),\n reason: z.string().optional(),\n outcome: z.enum(['success', 'failure', 'replaced', 'pending']),\n feedback: z.string().optional(),\n replaced_by: z.string().optional(),\n};\n\nexport const getStackSchema = {\n use_case: z.string().min(1),\n sub_needs: z\n .array(\n z.union([\n z.string().min(1),\n z.object({\n sub_need_type: z\n .string()\n .min(1)\n .max(50)\n .describe('Stack layer type, e.g. \"database\", \"auth\", \"web-framework\"'),\n keyword_sentence: z\n .string()\n .min(1)\n .max(500)\n .describe('Comma-separated keywords matching tool vocabulary, max 20 keywords'),\n }),\n ]),\n )\n .min(1)\n .max(8)\n .optional()\n .describe(\n 'Structured sub-needs from refine_requirement. Each is {sub_need_type, keyword_sentence} for keyword-matched search, or a plain string (legacy). The structured format dramatically improves accuracy.',\n ),\n constraints: z\n .object({\n deployment_model: z.enum(['self-hosted', 'cloud', 'embedded', 'serverless']).optional(),\n language: z.string().optional(),\n license: z.string().optional(),\n })\n .optional(),\n limit: z.number().int().positive().max(10).default(5),\n};\n\nexport const checkIssueSchema = {\n tool_name: z.string(),\n issue_title: z.string(),\n retry_count: z.number().int().min(0).default(0),\n docs_consulted: z.boolean().default(false),\n issue_url: z.string().url().optional(),\n};\n\nexport const checkCompatibilitySchema = {\n tool_a: z.string(),\n tool_b: z.string(),\n tool_a_version: z\n .string()\n .optional()\n .describe('Specific version of tool_a to evaluate (e.g., \"14.0.0\"). Default: latest.'),\n tool_b_version: z\n .string()\n .optional()\n .describe('Specific version of tool_b to evaluate (e.g., \"18.2.0\"). Default: latest.'),\n};\n\nexport const suggestGraphUpdateSchema = {\n suggestion_type: z.enum(['new_tool', 'new_edge', 'update_health', 'new_use_case']),\n data: z.object({\n tool_name: z.string().optional(),\n github_url: z.string().url().optional(),\n description: z.string().optional(),\n relationship: z\n .object({\n source_tool: z.string(),\n target_tool: z.string(),\n edge_type: z.enum([\n 'SOLVES',\n 'REQUIRES',\n 'INTEGRATES_WITH',\n 'REPLACES',\n 'CONFLICTS_WITH',\n 'POPULAR_WITH',\n 'BREAKS_FROM',\n 'COMPATIBLE_WITH',\n ]),\n evidence: z.string().optional(),\n })\n .optional(),\n use_case: z\n .object({\n name: z.string(),\n description: z.string(),\n tools: z.array(z.string()).optional(),\n })\n .optional(),\n }),\n query_id: z.string().uuid().optional(),\n confidence: z.number().min(0).max(1).default(0.5),\n};\n\nexport const compareToolsSchema = {\n tool_a: z.string().min(1),\n tool_b: z.string().min(1),\n use_case: z.string().optional(),\n project_config: z.string().max(100_000).optional(),\n};\n\nexport const toolcairnInitSchema = {\n agent: z.enum(['claude', 'cursor', 'windsurf', 'copilot', 'copilot-cli', 'opencode', 'generic']),\n project_root: z.string().min(1),\n server_path: z.string().optional(),\n};\n\nexport const readProjectConfigSchema = {\n project_root: z.string().min(1),\n /** When true, the response includes per-tool `locations[]`. Default false (smaller payload). */\n include_locations: z.boolean().optional(),\n};\n\nexport const updateProjectConfigSchema = {\n project_root: z.string().min(1),\n action: z.enum(['add_tool', 'remove_tool', 'update_tool', 'add_evaluation']),\n tool_name: z.string().min(1),\n data: z.record(z.string(), z.unknown()).optional(),\n};\n\nexport const classifyPromptSchema = {\n prompt: z.string().min(1).max(2000),\n project_tools: z.array(z.string()).optional(),\n};\n\nexport const verifySuggestionSchema = {\n query: z.string().min(1).max(500),\n agent_suggestions: z.array(z.string().min(1)).min(1).max(10),\n};\n\nexport const refineRequirementSchema = {\n prompt: z.string().min(1).max(2000),\n classification: z.enum([\n 'tool_discovery',\n 'stack_building',\n 'tool_comparison',\n 'tool_configuration',\n ]),\n project_context: z\n .object({\n existing_tools: z.array(z.string()).optional(),\n language: z.string().optional(),\n framework: z.string().optional(),\n })\n .optional(),\n};\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nexport function okResult(data: unknown): CallToolResult {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ ok: true, data }) }],\n };\n}\n\nexport function errResult(error: string, message: string): CallToolResult {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ ok: false, error, message }) }],\n isError: true,\n };\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:classify-prompt' });\n\n// Categories a prompt can fall into\nexport type PromptClassification =\n | 'tool_discovery' // needs to find/select tools or libraries\n | 'stack_building' // needs to compose multiple tools into a stack\n | 'tool_configuration' // already has a tool, needs setup/config help\n | 'tool_comparison' // wants to compare two or more tools\n | 'debugging' // hitting an error or unexpected behavior\n | 'general_coding'; // architecture, business logic, no tool selection needed\n\n// Categories where ToolCairn search is useful\nconst TOOL_REQUIRED_CLASSIFICATIONS: PromptClassification[] = [\n 'tool_discovery',\n 'stack_building',\n 'tool_comparison',\n];\n\nexport async function handleClassifyPrompt(args: {\n prompt: string;\n project_tools?: string[];\n}) {\n try {\n logger.info({ promptLen: args.prompt.length }, 'classify_prompt called');\n\n const projectToolsContext =\n args.project_tools && args.project_tools.length > 0\n ? `\\n\\nThe project already uses: ${args.project_tools.join(', ')}. Consider whether the prompt relates to tools already confirmed in the project.`\n : '';\n\n // Build a structured prompt the agent uses to classify\n const classification_prompt = `Classify the following developer prompt into exactly ONE of these categories:\n\nCategories:\n- tool_discovery: The developer needs to find, select, or identify a tool, library, framework, or service\n- stack_building: The developer needs to compose multiple tools together to build a complete system\n- tool_comparison: The developer wants to compare two or more specific tools\n- tool_configuration: The developer already has a tool chosen and needs help configuring or using it\n- debugging: The developer is encountering an error, bug, or unexpected behavior\n- general_coding: Architecture, business logic, algorithms — no new tool selection is needed\n\nRules:\n1. If the prompt involves building something \"from scratch\" or asks for tech stack recommendations, classify as stack_building\n2. If the prompt mentions a specific tool and asks \"should I use X or Y\", classify as tool_comparison\n3. If the prompt is about implementing features WITHOUT mentioning specific tools, classify as tool_discovery\n4. If the prompt mentions an error message, traceback, or \"not working\", classify as debugging\n5. Respond with ONLY the category name, nothing else\n\nPrompt to classify:\n\"\"\"\n${args.prompt}\n\"\"\"${projectToolsContext}\n\nYour response (one category name only):`;\n\n const needs_tool_search_prompt = `Based on this classification, determine if ToolCairn tool search should be invoked.\nRespond with 1 if the classification is one of: tool_discovery, stack_building, tool_comparison\nRespond with 0 if the classification is: tool_configuration, debugging, general_coding\nRespond with ONLY 0 or 1.`;\n\n return okResult({\n classification_prompt,\n needs_tool_search_prompt,\n valid_classifications: [\n 'tool_discovery',\n 'stack_building',\n 'tool_comparison',\n 'tool_configuration',\n 'debugging',\n 'general_coding',\n ] as PromptClassification[],\n tool_required_if: TOOL_REQUIRED_CLASSIFICATIONS,\n instructions:\n 'Step 1: Send classification_prompt to the LLM and get a classification. Step 2: If classification is in tool_required_if, call refine_requirement with the classification. Otherwise, proceed without ToolCairn search.',\n });\n } catch (e) {\n logger.error({ err: e }, 'classify_prompt failed');\n return errResult('classify_error', e instanceof Error ? e.message : String(e));\n }\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport { type PendingAuditEntry, mutateConfig } from '../config-store/index.js';\nimport { type BatchResolveFn, scanProject } from '../discovery/index.js';\nimport {\n type AgentType,\n getInstructionsForAgent,\n getMcpConfigEntry,\n getOpenCodeMcpEntry,\n} from '../templates/agent-instructions.js';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:toolcairn-init' });\n\nexport interface HandleToolcairnInitDeps {\n /** Injected resolver — the server wires this to ToolCairnClient.batchResolve. */\n batchResolve?: BatchResolveFn;\n}\n\n/**\n * One-call project setup for the ToolCairn MCP.\n *\n * Does ALL of the following server-side:\n * 1. Walks every workspace (pnpm/yarn/cargo/go-work/nx/lerna/turbo), depth-capped.\n * 2. Parses every manifest + lockfile across 12 ecosystems.\n * 3. Calls the engine batch-resolve endpoint to classify which tools are\n * indexed in the ToolCairn graph (source: \"toolcairn\") vs local-only (source: \"non_oss\").\n * 4. Detects primary languages by file-extension count.\n * 5. Detects frameworks using graph categories (primary) + offline fallback map.\n * 6. Atomically writes `.toolcairn/config.json` (v1.1 schema) + appends to\n * `.toolcairn/audit-log.jsonl`. Cross-process locked.\n *\n * Still returns `setup_steps` for the agent to execute — but ONLY for files the\n * MCP server has no business touching:\n * - CLAUDE.md / .cursorrules / etc. (user-maintained instruction docs)\n * - .mcp.json (user-maintained client config)\n * - .gitignore (user-maintained)\n */\nexport async function handleToolcairnInit(\n args: {\n agent: AgentType;\n project_root: string;\n server_path?: string;\n },\n deps: HandleToolcairnInitDeps = {},\n) {\n try {\n logger.info({ agent: args.agent, project_root: args.project_root }, 'toolcairn_init called');\n\n // 1. Programmatic scan + server-side config write.\n const scan = await scanProject(args.project_root, { batchResolve: deps.batchResolve });\n\n const audit: PendingAuditEntry = {\n action: 'init',\n tool: '__project__',\n reason: `Auto-discovered via toolcairn_init: ${scan.tools.length} tools across ${scan.scan_metadata.ecosystems_scanned.length} ecosystems`,\n };\n\n const { config, audit_entry, bootstrapped, migrated } = await mutateConfig(\n args.project_root,\n (cfg) => {\n cfg.project.name = scan.name;\n cfg.project.languages = scan.languages;\n cfg.project.frameworks = scan.frameworks;\n cfg.project.subprojects = scan.subprojects;\n // Replace the whole confirmed list — init is authoritative.\n cfg.tools.confirmed = scan.tools;\n cfg.scan_metadata = scan.scan_metadata;\n },\n audit,\n );\n\n // 2. Agent-side setup steps (instruction doc + .mcp.json + .gitignore)\n const instructions = getInstructionsForAgent(args.agent);\n const isOpenCode = args.agent === 'opencode';\n const mcpConfigEntry = isOpenCode\n ? getOpenCodeMcpEntry(args.server_path)\n : getMcpConfigEntry(args.server_path);\n const mcpConfigFile = isOpenCode ? 'opencode.json' : '.mcp.json';\n\n const mcpContent = isOpenCode\n ? JSON.stringify({ mcp: mcpConfigEntry }, null, 2)\n : JSON.stringify({ mcpServers: mcpConfigEntry }, null, 2);\n\n const setupSteps = [\n {\n step: 1,\n action: 'append-or-create',\n file: instructions.file_path,\n content: instructions.content,\n note: `Append the ToolCairn rules block to ${instructions.file_path} (or create it if missing).`,\n },\n {\n step: 2,\n action: 'merge-or-create',\n file: mcpConfigFile,\n content: mcpContent,\n note: isOpenCode\n ? `Merge the toolcairn entry into ${mcpConfigFile} under \"mcp\".`\n : `Merge the toolcairn entry into ${mcpConfigFile} under \"mcpServers\".`,\n },\n {\n step: 3,\n action: 'append',\n file: '.gitignore',\n content:\n '\\n# ToolCairn\\n.toolcairn/events.jsonl\\n.toolcairn/audit-log.jsonl\\n.toolcairn/audit-log.archive.jsonl\\n.toolcairn/config.lock\\n',\n note: 'Ignore runtime/audit files. config.json should be committed so teammates share tool intelligence.',\n },\n ];\n\n const tool_counts = {\n total: config.tools.confirmed.length,\n indexed: config.tools.confirmed.filter((t) => t.source === 'toolcairn').length,\n non_oss: config.tools.confirmed.filter((t) => t.source === 'non_oss').length,\n };\n\n return okResult({\n agent: args.agent,\n instruction_file: instructions.file_path,\n config_path: '.toolcairn/config.json',\n audit_log_path: '.toolcairn/audit-log.jsonl',\n events_path: '.toolcairn/events.jsonl',\n mcp_config_entry: mcpConfigEntry,\n setup_steps: setupSteps,\n scan_summary: {\n project_name: scan.name,\n languages: scan.languages.map((l) => ({ name: l.name, file_count: l.file_count })),\n frameworks: scan.frameworks,\n subprojects: scan.subprojects,\n tool_counts,\n warnings: scan.warnings,\n scan_metadata: scan.scan_metadata,\n },\n bootstrapped,\n migrated,\n last_audit_entry: audit_entry,\n next_steps:\n 'Config written. Apply the setup_steps above (CLAUDE.md rules + .mcp.json merge + .gitignore). Then proceed with normal tool calls — the server owns .toolcairn/ going forward.',\n });\n } catch (e) {\n logger.error({ err: e }, 'toolcairn_init failed');\n return errResult('init_error', e instanceof Error ? e.message : String(e));\n }\n}\n","export {\n AUDIT_ARCHIVE_FILE,\n AUDIT_LOG_FILE,\n CONFIG_DIR,\n CONFIG_FILE,\n joinAuditArchivePath,\n joinAuditPath,\n joinConfigDir,\n joinConfigPath,\n joinLockPath,\n LOCK_FILE,\n} from './paths.js';\nexport { readConfig, type ReadConfigResult } from './read.js';\nexport { writeConfig } from './write.js';\nexport { appendAudit, bulkAppendAudit, readLiveAudit } from './audit.js';\nexport { migrateToV1_1, type MigrateResult } from './migrate.js';\nexport { mutateConfig, type Mutator, type MutateResult, type PendingAuditEntry } from './mutate.js';\nexport { emptySkeleton } from './skeleton.js';\n","import { join } from 'node:path';\n\nexport const CONFIG_DIR = '.toolcairn';\nexport const CONFIG_FILE = 'config.json';\nexport const AUDIT_LOG_FILE = 'audit-log.jsonl';\nexport const AUDIT_ARCHIVE_FILE = 'audit-log.archive.jsonl';\nexport const LOCK_FILE = 'config.lock';\n\nexport function joinConfigDir(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR);\n}\n\nexport function joinConfigPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, CONFIG_FILE);\n}\n\nexport function joinAuditPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, AUDIT_LOG_FILE);\n}\n\nexport function joinAuditArchivePath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, AUDIT_ARCHIVE_FILE);\n}\n\nexport function joinLockPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_DIR, LOCK_FILE);\n}\n","import { readFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ToolPilotProjectConfig } from '@toolcairn/types';\nimport { fileExists } from '../discovery/util/fs.js';\nimport { CONFIG_DIR, joinConfigPath } from './paths.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:config-store' });\n\nexport interface ReadConfigResult {\n /** Parsed config, or null when config.json is absent (caller should bootstrap). */\n config: ToolPilotProjectConfig | null;\n /** Absolute path we attempted to read. */\n path: string;\n /** When parsing failed, the corrupt file is renamed here; null means no corruption. */\n corrupt_backup_path: string | null;\n}\n\n/**\n * Reads `.toolcairn/config.json` from the project root.\n *\n * - Returns `{ config: null }` when the file does not exist (no error).\n * - On JSON parse failure: renames the corrupt file to\n * `.toolcairn/config.json.corrupt.<ISO-timestamp>` and returns `{ config: null }`\n * — callers will bootstrap a fresh skeleton without clobbering recoverable data.\n */\nexport async function readConfig(projectRoot: string): Promise<ReadConfigResult> {\n const configPath = joinConfigPath(projectRoot);\n\n if (!(await fileExists(configPath))) {\n return { config: null, path: configPath, corrupt_backup_path: null };\n }\n\n let raw: string;\n try {\n raw = await readFile(configPath, 'utf-8');\n } catch (err) {\n logger.error({ err, configPath }, 'Failed to read config.json');\n throw err;\n }\n\n try {\n const parsed = JSON.parse(raw) as ToolPilotProjectConfig;\n return { config: parsed, path: configPath, corrupt_backup_path: null };\n } catch (err) {\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backup = join(projectRoot, CONFIG_DIR, `config.json.corrupt.${stamp}`);\n try {\n await rename(configPath, backup);\n logger.warn({ configPath, backup, err }, 'config.json was unparseable — moved to backup');\n } catch (renameErr) {\n logger.error({ err: renameErr, configPath, backup }, 'Failed to rename corrupt config.json');\n }\n return { config: null, path: configPath, corrupt_backup_path: backup };\n }\n}\n","import { access, readdir, stat } from 'node:fs/promises';\n\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function isDir(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** Directories that discovery + language-detect never descend into. */\nexport const IGNORED_DIRS = new Set([\n 'node_modules',\n '.git',\n '.hg',\n '.svn',\n 'dist',\n 'build',\n 'out',\n '.next',\n '.turbo',\n '.nuxt',\n 'target', // rust, java\n 'vendor', // go, ruby, composer\n '__pycache__',\n '.venv',\n 'venv',\n '.tox',\n '.pytest_cache',\n '.mypy_cache',\n 'bin',\n 'obj', // dotnet\n '.gradle',\n '.idea',\n '.vscode',\n '.DS_Store',\n 'coverage',\n '.cache',\n '.pnpm-store',\n]);\n\n/** Yields absolute paths of every dir the walker should consider. */\nexport async function* walkDirs(root: string, maxDepth = 6): AsyncGenerator<string> {\n yield root;\n yield* walkDirsInner(root, 0, maxDepth);\n}\n\nasync function* walkDirsInner(\n dir: string,\n depth: number,\n maxDepth: number,\n): AsyncGenerator<string> {\n if (depth >= maxDepth) return;\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n if (entry.name.startsWith('.') && !['.github', '.claude', '.toolcairn'].includes(entry.name)) {\n continue;\n }\n const full = `${dir}/${entry.name}`;\n yield full;\n yield* walkDirsInner(full, depth + 1, maxDepth);\n }\n}\n","import { mkdir } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ToolPilotProjectConfig } from '@toolcairn/types';\nimport writeFileAtomic from 'write-file-atomic';\nimport { joinConfigDir, joinConfigPath } from './paths.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:config-store' });\n\n/**\n * Atomically writes config.json.\n *\n * Uses `write-file-atomic` which:\n * - Writes to a same-dir temp file (avoids EXDEV on different volumes).\n * - fsyncs the temp file and the parent directory (crash-safe).\n * - Renames to the target (overwrites on Windows via MoveFileExW).\n * - Retries automatically on EBUSY/EPERM (Windows AV handle contention).\n *\n * Caller MUST hold the cross-process lock — see mutate.ts.\n */\nexport async function writeConfig(\n projectRoot: string,\n config: ToolPilotProjectConfig,\n): Promise<void> {\n // Ensure .toolcairn/ exists (no-op after first write, cheap).\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n\n const configPath = joinConfigPath(projectRoot);\n const serialised = `${JSON.stringify(config, null, 2)}\\n`;\n\n await writeFileAtomic(configPath, serialised);\n logger.debug({ configPath, bytes: serialised.length }, 'config.json written atomically');\n}\n","import { appendFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfigAuditEntry } from '@toolcairn/types';\nimport writeFileAtomic from 'write-file-atomic';\nimport { fileExists } from '../discovery/util/fs.js';\nimport { joinAuditArchivePath, joinAuditPath, joinConfigDir } from './paths.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:audit-log' });\n\n/** Maximum entries retained in the live audit-log.jsonl before FIFO archive. */\nconst MAX_LIVE_ENTRIES = 1000;\n/** Entries moved to the archive when the live file exceeds MAX_LIVE_ENTRIES. */\nconst ARCHIVE_BATCH = 500;\n\n/**\n * Appends one entry to `.toolcairn/audit-log.jsonl`, creating the file if absent.\n *\n * After append, if the live file has grown beyond MAX_LIVE_ENTRIES, the oldest\n * ARCHIVE_BATCH lines are moved to `.toolcairn/audit-log.archive.jsonl` and the\n * live file is truncated to the remaining tail.\n *\n * Caller MUST hold the cross-process lock.\n */\nexport async function appendAudit(projectRoot: string, entry: ConfigAuditEntry): Promise<void> {\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n const auditPath = joinAuditPath(projectRoot);\n const line = `${JSON.stringify(entry)}\\n`;\n await appendFile(auditPath, line, 'utf-8');\n\n // Rotation check — counts lines in-place; cheap for files under a few MB.\n await rotateIfNeeded(projectRoot, auditPath);\n}\n\n/**\n * Bulk-appends many entries in one flush. Used during 1.0 → 1.1 migration when\n * the legacy `audit_log[]` is relocated into the jsonl file.\n */\nexport async function bulkAppendAudit(\n projectRoot: string,\n entries: ConfigAuditEntry[],\n): Promise<void> {\n if (entries.length === 0) return;\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n const auditPath = joinAuditPath(projectRoot);\n const payload = entries.map((e) => `${JSON.stringify(e)}\\n`).join('');\n await appendFile(auditPath, payload, 'utf-8');\n await rotateIfNeeded(projectRoot, auditPath);\n}\n\n/** Returns all audit entries in the live file (not the archive). Parse errors are skipped. */\nexport async function readLiveAudit(projectRoot: string): Promise<ConfigAuditEntry[]> {\n const auditPath = joinAuditPath(projectRoot);\n if (!(await fileExists(auditPath))) return [];\n const raw = await readFile(auditPath, 'utf-8');\n return parseJsonl(raw);\n}\n\nasync function rotateIfNeeded(projectRoot: string, auditPath: string): Promise<void> {\n const raw = await readFile(auditPath, 'utf-8');\n const lines = raw.split('\\n').filter((l) => l.trim().length > 0);\n if (lines.length <= MAX_LIVE_ENTRIES) return;\n\n const archiveBatch = lines.slice(0, ARCHIVE_BATCH);\n const keep = lines.slice(ARCHIVE_BATCH);\n const archivePath = joinAuditArchivePath(projectRoot);\n\n try {\n // Archive append (never truncates) — then atomic-write the truncated live file.\n await appendFile(archivePath, `${archiveBatch.join('\\n')}\\n`, 'utf-8');\n // Atomic truncate by writing new content to a temp + rename.\n const newContent = `${keep.join('\\n')}\\n`;\n await writeFileAtomic(auditPath, newContent);\n logger.info(\n { archived: archiveBatch.length, retained: keep.length },\n 'audit-log.jsonl rotated',\n );\n } catch (err) {\n logger.warn({ err, auditPath, archivePath }, 'Audit-log rotation failed — live file intact');\n }\n}\n\nfunction parseJsonl(raw: string): ConfigAuditEntry[] {\n const out: ConfigAuditEntry[] = [];\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue;\n try {\n out.push(JSON.parse(line) as ConfigAuditEntry);\n } catch {\n // Skip malformed line — do not break the caller\n }\n }\n return out;\n}\n\n/** Test helper — blow away the audit log files. Not exported from the barrel. */\nexport async function _resetAudit(projectRoot: string): Promise<void> {\n for (const p of [joinAuditPath(projectRoot), joinAuditArchivePath(projectRoot)]) {\n try {\n await rm(p);\n } catch {\n /* ignore */\n }\n }\n // Re-create empty live file so fresh appends start clean.\n try {\n await writeFile(joinAuditPath(projectRoot), '', 'utf-8');\n } catch {\n /* ignore */\n }\n}\n","import type { ConfigAuditEntry, ToolPilotProjectConfig } from '@toolcairn/types';\nimport { bulkAppendAudit } from './audit.js';\n\nexport interface MigrateResult {\n migrated: boolean;\n /** True iff the doc was at version 1.0 and was upgraded in place. */\n was_v1_0: boolean;\n /** Legacy audit entries that were moved out of the config into audit-log.jsonl. */\n legacy_audit_entries: ConfigAuditEntry[];\n}\n\n/**\n * Migrates a parsed config in place from v1.0 to v1.1.\n *\n * - Promotes `project.language` (string) to `project.languages` (array).\n * - Promotes `project.framework` (string) to `project.frameworks` (array).\n * - Ensures every ConfirmedTool has `locations: []` (empty by default — re-scan\n * fills in accurate data on the first toolcairn_init after upgrade).\n * - Relocates inline `audit_log[]` into audit-log.jsonl and drops the field from\n * the in-memory config.\n *\n * Does NOT write to disk — caller (mutate.ts) is responsible for the atomic write\n * and for bulk-appending the returned `legacy_audit_entries` to audit-log.jsonl.\n */\nexport async function migrateToV1_1(\n config: ToolPilotProjectConfig,\n projectRoot: string,\n): Promise<MigrateResult> {\n if (config.version === '1.1') {\n // Already on target schema — just make sure locations[] exists so handlers\n // can rely on it being present.\n for (const tool of config.tools.confirmed) {\n if (!tool.locations) tool.locations = [];\n }\n return { migrated: false, was_v1_0: false, legacy_audit_entries: [] };\n }\n\n // Upgrade project metadata.\n if (!config.project.languages) {\n config.project.languages = config.project.language\n ? [{ name: config.project.language, file_count: 0, workspaces: ['.'] }]\n : [];\n }\n if (!config.project.frameworks) {\n config.project.frameworks = config.project.framework\n ? [\n {\n name: config.project.framework,\n ecosystem: 'npm',\n workspace: '.',\n source: 'local',\n },\n ]\n : [];\n }\n if (!config.project.subprojects) config.project.subprojects = [];\n\n // Every ConfirmedTool gets a locations[] (empty placeholder — first re-scan fills it).\n for (const tool of config.tools.confirmed) {\n if (!tool.locations) tool.locations = [];\n }\n\n // Extract legacy audit entries + append migration marker.\n const legacy = config.audit_log ?? [];\n delete config.audit_log;\n\n const now = new Date().toISOString();\n const migrationEntry: ConfigAuditEntry = {\n action: 'migrate',\n tool: '__schema__',\n timestamp: now,\n reason:\n 'Schema 1.0 → 1.1: audit_log relocated to audit-log.jsonl; languages/frameworks expanded to arrays',\n };\n config.last_audit_entry = migrationEntry;\n config.version = '1.1';\n\n // Persist legacy entries + the migration entry into the audit-log.jsonl file.\n // (The mutate.ts orchestration still holds the cross-process lock at this point.)\n await bulkAppendAudit(projectRoot, [...legacy, migrationEntry]);\n\n return { migrated: true, was_v1_0: true, legacy_audit_entries: legacy };\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfigAuditEntry, ToolPilotProjectConfig } from '@toolcairn/types';\nimport lockfile from 'proper-lockfile';\nimport { fileExists } from '../discovery/util/fs.js';\nimport { appendAudit } from './audit.js';\nimport { migrateToV1_1 } from './migrate.js';\nimport { joinConfigDir, joinConfigPath } from './paths.js';\nimport { readConfig } from './read.js';\nimport { emptySkeleton } from './skeleton.js';\nimport { writeConfig } from './write.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:config-store' });\n\nexport type Mutator = (config: ToolPilotProjectConfig) => void | Promise<void>;\n\n/** The audit entry to attach, sans timestamp (mutate.ts stamps it). */\nexport type PendingAuditEntry = Omit<ConfigAuditEntry, 'timestamp'>;\n\nexport interface MutateResult {\n config: ToolPilotProjectConfig;\n audit_entry: ConfigAuditEntry;\n /** True iff we bootstrapped a fresh config.json on this call. */\n bootstrapped: boolean;\n /** True iff the config on disk was v1.0 and was migrated in the same write. */\n migrated: boolean;\n}\n\n/**\n * The single supported entry point for mutating `.toolcairn/config.json`.\n *\n * Flow (under cross-process advisory lock):\n * 1. Ensure `.toolcairn/` exists + acquire `.toolcairn/config.lock`.\n * 2. Read config.json (or bootstrap a fresh v1.1 skeleton if absent).\n * 3. If schema is v1.0, migrate in place and relocate legacy audit entries.\n * 4. Apply the caller-supplied `mutator(config)` on the in-memory object.\n * 5. Stamp `{...audit, timestamp: now}` into `config.last_audit_entry`.\n * 6. Atomic-write `config.json` (write-file-atomic: fsync + parent dirsync + EBUSY retry).\n * 7. Append the audit entry to `.toolcairn/audit-log.jsonl` (FIFO-archives at 1000 entries).\n * 8. Release the lock.\n *\n * The lock survives process crashes (stale-lock timeout = 10s); if a prior holder\n * crashed mid-write, the write-file-atomic temp file is naturally cleaned up by a\n * subsequent run.\n */\nexport async function mutateConfig(\n projectRoot: string,\n mutator: Mutator,\n audit: PendingAuditEntry,\n): Promise<MutateResult> {\n // proper-lockfile locks a real file by creating `<file>.lock/` directory.\n // We lock config.json itself (idiomatic), seeding an empty skeleton first when absent.\n // Record whether the real config.json existed BEFORE we seeded anything — the\n // \"bootstrapped\" flag we return reflects that pre-seed state.\n const configPath = joinConfigPath(projectRoot);\n const preExisted = await fileExists(configPath);\n await ensureLockableDir(projectRoot);\n\n const release = await lockfile.lock(configPath, {\n stale: 10_000,\n retries: { retries: 5, minTimeout: 50, factor: 2, maxTimeout: 500 },\n realpath: false,\n });\n\n try {\n // 1. Read\n const { config: existing } = await readConfig(projectRoot);\n let config: ToolPilotProjectConfig;\n const bootstrapped = !preExisted;\n let migrated = false;\n\n if (!existing) {\n config = emptySkeleton();\n logger.info({ projectRoot }, 'Bootstrapping fresh .toolcairn/config.json');\n } else {\n config = existing;\n }\n\n // 2. Migrate if needed (before mutator so mutators see the v1.1 shape).\n if (config.version === '1.0') {\n const result = await migrateToV1_1(config, projectRoot);\n migrated = result.migrated;\n } else {\n // Ensure v1.1 invariants even if the file was hand-edited\n for (const tool of config.tools.confirmed) {\n if (!tool.locations) tool.locations = [];\n }\n if (!config.project.languages) config.project.languages = [];\n if (!config.project.frameworks) config.project.frameworks = [];\n if (!config.project.subprojects) config.project.subprojects = [];\n }\n\n // 3. Caller mutation.\n await mutator(config);\n\n // 4. Stamp audit entry.\n const now = new Date().toISOString();\n const entry: ConfigAuditEntry = { ...audit, timestamp: now };\n config.last_audit_entry = entry;\n config.version = '1.1';\n\n // 5. Atomic write + audit append.\n await writeConfig(projectRoot, config);\n await appendAudit(projectRoot, entry);\n\n return { config, audit_entry: entry, bootstrapped, migrated };\n } finally {\n try {\n await release();\n } catch (err) {\n logger.warn({ err, configPath }, 'Failed to release config lock — may be stale');\n }\n }\n}\n\n/**\n * proper-lockfile requires the lock target to exist on disk. For first-time\n * runs we seed an empty v1.1 skeleton; subsequent runs no-op.\n */\nasync function ensureLockableDir(projectRoot: string): Promise<void> {\n await mkdir(joinConfigDir(projectRoot), { recursive: true });\n\n const configPath = joinConfigPath(projectRoot);\n if (!(await fileExists(configPath))) {\n try {\n await writeFile(configPath, `${JSON.stringify(emptySkeleton(), null, 2)}\\n`, 'utf-8');\n } catch (err) {\n // Tolerable — another process may have seeded concurrently.\n logger.debug({ err, configPath }, 'Bootstrap seed skipped (likely race)');\n }\n }\n}\n","import type { ToolPilotProjectConfig } from '@toolcairn/types';\n\n/** A fresh, empty v1.1 config. Used when bootstrapping a project for the first time. */\nexport function emptySkeleton(name = ''): ToolPilotProjectConfig {\n return {\n version: '1.1',\n project: {\n name,\n languages: [],\n frameworks: [],\n subprojects: [],\n },\n tools: {\n confirmed: [],\n pending_evaluation: [],\n },\n last_audit_entry: null,\n };\n}\n","export { scanProject } from './scan-project.js';\nexport type {\n BatchResolveFn,\n ScanProjectOptions,\n ScanProjectResult,\n} from './scan-project.js';\nexport type { BatchResolveResult } from './frameworks/detect.js';\nexport type { DetectedTool, ParseResult, Parser, ParserInput } from './types.js';\n","import { readFile } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport type {\n ConfirmedTool,\n DiscoveryWarning,\n Ecosystem,\n MatchMethod,\n ProjectFramework,\n ProjectLanguage,\n ProjectSubproject,\n ScanMetadata,\n ToolLocation,\n ToolSource,\n} from '@toolcairn/types';\nimport { detectEcosystems } from './ecosystem-detect.js';\nimport { type BatchResolveResult, detectFrameworks } from './frameworks/detect.js';\nimport { detectLanguages } from './language-detect.js';\nimport { PARSERS } from './parsers/index.js';\nimport { RESOLVERS } from './resolvers/index.js';\nimport type { DetectedTool } from './types.js';\nimport { fileExists } from './util/fs.js';\nimport { toRelPosix } from './workspaces/glob.js';\nimport { discoverWorkspaces } from './workspaces/walker.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:scan-project' });\n\n/** Per-input payload for the MCP-to-engine batch-resolve call. */\nexport type BatchResolveItem = {\n name: string;\n ecosystem: Ecosystem;\n /**\n * Canonical package name from the INSTALLED manifest (e.g. resolves npm\n * aliased installs). Engine uses this over `name` when present.\n */\n canonical_package_name?: string;\n /**\n * Authoritative repository URL extracted from the installed package's own\n * manifest. Drives the engine's `exact_github` match tier — unambiguous\n * even when registry keys are mis-indexed.\n */\n github_url?: string;\n};\n\n/** Resolver signature — the MCP handler injects a function backed by @toolcairn/remote. */\nexport type BatchResolveFn = (items: BatchResolveItem[]) => Promise<{\n results: BatchResolveResult[];\n warnings: DiscoveryWarning[];\n /** Match methods per resolved entry (keyed by \"ecosystem:name\"). */\n methods: Map<string, MatchMethod>;\n /** GitHub urls per resolved entry (keyed by \"ecosystem:name\"). */\n githubUrls: Map<string, string>;\n}>;\n\nexport interface ScanProjectOptions {\n /** Injected resolver. Omit to run in offline-only mode (all tools → non_oss). */\n batchResolve?: BatchResolveFn;\n /** Maximum workspace-recursion depth. */\n maxDepth?: number;\n}\n\nexport interface ScanProjectResult {\n name: string;\n languages: ProjectLanguage[];\n frameworks: ProjectFramework[];\n subprojects: ProjectSubproject[];\n /** Tools shaped for direct insertion into `config.tools.confirmed`. */\n tools: ConfirmedTool[];\n warnings: DiscoveryWarning[];\n scan_metadata: ScanMetadata;\n}\n\n/**\n * Scan a project root and return everything needed to populate a v1.1 config.\n *\n * Steps:\n * 1. Discover all workspace roots (depth-capped recursive walk).\n * 2. For each workspace, detect ecosystems via manifest presence.\n * 3. Parse every (workspace, ecosystem) pair in parallel.\n * 4. Merge duplicate tools across workspaces into one ConfirmedTool with locations[].\n * 5. Detect languages (file-extension counts excluding vendor/build dirs).\n * 6. Call batchResolve to classify each (ecosystem, name) against the ToolCairn graph.\n * 7. Build frameworks[] using the batch-resolve categories + local fallback.\n */\nexport async function scanProject(\n projectRoot: string,\n options: ScanProjectOptions = {},\n): Promise<ScanProjectResult> {\n const start = Date.now();\n const { batchResolve, maxDepth = 5 } = options;\n const absRoot = resolve(projectRoot);\n const warnings: DiscoveryWarning[] = [];\n\n logger.info({ projectRoot: absRoot }, 'Starting project scan');\n\n // --- 1. Workspace discovery --------------------------------------------\n const { paths: workspaceAbs, warnings: wsWarnings } = await discoverWorkspaces(absRoot, maxDepth);\n warnings.push(...wsWarnings);\n\n // --- 2+3. Per-workspace per-ecosystem parsing --------------------------\n const allDetected: DetectedTool[] = [];\n const ecosystemsScanned = new Set<Ecosystem>();\n const parsersFailed: string[] = [];\n const subprojects: ProjectSubproject[] = [];\n\n // Run all parser invocations concurrently — they're pure file reads.\n const parseTasks: Promise<void>[] = [];\n for (const wsDir of workspaceAbs) {\n const wsRel = toRelPosix(absRoot, wsDir);\n const ecosystems = await detectEcosystems(wsDir);\n for (const eco of ecosystems) {\n ecosystemsScanned.add(eco);\n const parser = PARSERS[eco];\n parseTasks.push(\n parser({ workspace_dir: wsDir, workspace_rel: wsRel, project_root: absRoot })\n .then((result) => {\n allDetected.push(...result.tools);\n warnings.push(...result.warnings);\n if (result.tools.length > 0 && wsRel !== '') {\n // Track non-root workspaces that actually had tools under an ecosystem\n const existing = subprojects.find((s) => s.path === wsRel && s.ecosystem === eco);\n if (!existing) {\n subprojects.push({\n path: wsRel,\n manifest: primaryManifestForEcosystem(eco),\n ecosystem: eco,\n });\n }\n }\n })\n .catch((err: unknown) => {\n parsersFailed.push(`${eco}@${wsRel || '.'}`);\n warnings.push({\n scope: `parser:${eco}`,\n path: wsRel || '.',\n message: `Parser crashed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }),\n );\n }\n }\n await Promise.all(parseTasks);\n\n // --- 4. Merge dedupe by (ecosystem, name) → locations[] ---------------\n const mergedMap = new Map<\n string,\n {\n name: string;\n ecosystem: Ecosystem;\n locations: ToolLocation[];\n /** From local resolver — sent to engine so it can use exact_channel via the true package name. */\n canonical_package_name?: string;\n /** From local resolver — authoritative github_url the client extracted from the installed manifest. */\n local_github_url?: string;\n }\n >();\n for (const dep of allDetected) {\n const key = `${dep.ecosystem}:${dep.name}`;\n const location: ToolLocation = {\n workspace_path: dep.workspace_path,\n manifest_file: dep.manifest_file,\n section: dep.section,\n ecosystem: dep.ecosystem,\n version_constraint: dep.version_constraint,\n resolved_version: dep.resolved_version,\n };\n const existing = mergedMap.get(key);\n if (existing) {\n // Avoid dupe-location when the same parser picks up the same dep twice\n const sameLoc = existing.locations.some(\n (l) =>\n l.workspace_path === location.workspace_path &&\n l.manifest_file === location.manifest_file &&\n l.section === location.section,\n );\n if (!sameLoc) existing.locations.push(location);\n } else {\n mergedMap.set(key, { name: dep.name, ecosystem: dep.ecosystem, locations: [location] });\n }\n }\n\n // --- 4.5. Per-tool local identity enrichment --------------------------\n // Walk each merged entry, invoke the per-ecosystem resolver against the\n // first location whose workspace has the installed package available.\n // This is the cheapest reliable source of (canonical_package_name, github_url)\n // — read from the user's installed dep's own manifest instead of trusting\n // the server-side `package_managers` index.\n await Promise.all(\n [...mergedMap.values()].map(async (entry) => {\n const resolver = RESOLVERS[entry.ecosystem];\n if (!resolver) return;\n for (const loc of entry.locations) {\n const workspaceAbs = resolve(absRoot, loc.workspace_path);\n const hints = { resolved_version: loc.resolved_version };\n try {\n const identity = await resolver(workspaceAbs, absRoot, entry.name, hints);\n if (identity.canonical_package_name) {\n entry.canonical_package_name = identity.canonical_package_name;\n }\n if (identity.github_url) {\n entry.local_github_url = identity.github_url;\n }\n if (identity.canonical_package_name || identity.github_url) break;\n } catch (err) {\n logger.debug(\n {\n ecosystem: entry.ecosystem,\n name: entry.name,\n workspace: loc.workspace_path,\n err: err instanceof Error ? err.message : String(err),\n },\n 'Resolver threw — skipping this location',\n );\n }\n }\n }),\n );\n\n // --- 5. Language detection ---------------------------------------------\n const workspaceRels = workspaceAbs.map((abs) => toRelPosix(absRoot, abs));\n const languages = await detectLanguages(absRoot, workspaceRels);\n\n // --- 6. Batch-resolve against the graph -------------------------------\n const resolveInputs = [...mergedMap.values()].map(\n ({ name, ecosystem, canonical_package_name, local_github_url }) => ({\n name,\n ecosystem,\n canonical_package_name,\n github_url: local_github_url,\n }),\n );\n const resolved = new Map<string, BatchResolveResult>();\n const methods = new Map<string, MatchMethod>();\n const githubUrls = new Map<string, string>();\n\n if (batchResolve && resolveInputs.length > 0) {\n try {\n const r = await batchResolve(resolveInputs);\n for (const res of r.results) {\n const key = `${res.input.ecosystem}:${res.input.name}`;\n resolved.set(key, res);\n }\n for (const [k, v] of r.methods) methods.set(k, v);\n for (const [k, v] of r.githubUrls) githubUrls.set(k, v);\n warnings.push(...r.warnings);\n } catch (err) {\n warnings.push({\n scope: 'batch-resolve',\n message: `Failed to resolve tools against graph: ${err instanceof Error ? err.message : String(err)}. Falling back to local classification.`,\n });\n }\n } else if (!batchResolve) {\n warnings.push({\n scope: 'batch-resolve',\n message:\n 'No batchResolve client provided — running in offline-only mode; all tools classified as non_oss.',\n });\n }\n\n // --- 7. Framework detection --------------------------------------------\n const frameworks = detectFrameworks(allDetected, resolved);\n\n // --- 8. Assemble ConfirmedTool[] --------------------------------------\n const now = new Date().toISOString();\n const confirmed: ConfirmedTool[] = [];\n let toolsResolvedCount = 0;\n\n for (const { name, ecosystem, locations, local_github_url } of mergedMap.values()) {\n const key = `${ecosystem}:${name}`;\n const graph = resolved.get(key);\n const matchMethod = methods.get(key) ?? 'none';\n const matched = graph?.matched === true;\n if (matched) toolsResolvedCount++;\n\n const source: ToolSource = matched ? 'toolcairn' : 'non_oss';\n const canonical = graph?.tool?.canonical_name;\n const categories = graph?.tool?.categories;\n // Prefer the graph's canonical github_url (authoritative for the matched\n // Tool). When the engine has no match, fall back to the URL we pulled\n // locally from the installed package manifest — still strictly better\n // than `undefined` for agent-side reasoning.\n const github_url = githubUrls.get(key) ?? local_github_url;\n const version =\n locations.find((l) => l.resolved_version)?.resolved_version ??\n locations[0]?.version_constraint;\n\n confirmed.push({\n name,\n source,\n github_url,\n version,\n chosen_at: now,\n chosen_reason: 'Auto-detected from manifest during toolcairn_init scan',\n alternatives_considered: [],\n canonical_name: canonical,\n categories,\n match_method: matchMethod,\n locations,\n });\n }\n // Stable order: indexed first (alphabetical), then non-indexed (alphabetical)\n confirmed.sort((a, b) => {\n const rank = (t: ConfirmedTool) => (t.source === 'toolcairn' ? 0 : 1);\n if (rank(a) !== rank(b)) return rank(a) - rank(b);\n return a.name.localeCompare(b.name);\n });\n\n // Sort subprojects by path for deterministic output\n subprojects.sort((a, b) => a.path.localeCompare(b.path));\n\n const name = await inferProjectName(absRoot);\n const scan_metadata: ScanMetadata = {\n ecosystems_scanned: [...ecosystemsScanned].sort(),\n parsers_failed: parsersFailed.sort(),\n tools_resolved: toolsResolvedCount,\n tools_unresolved: confirmed.length - toolsResolvedCount,\n duration_ms: Date.now() - start,\n completed_at: now,\n };\n\n logger.info(\n {\n projectRoot: absRoot,\n workspaces: workspaceAbs.length,\n ecosystems: scan_metadata.ecosystems_scanned,\n tools: confirmed.length,\n resolved: toolsResolvedCount,\n languages: languages.map((l) => l.name),\n frameworks: frameworks.map((f) => f.name),\n duration_ms: scan_metadata.duration_ms,\n },\n 'Project scan complete',\n );\n\n return {\n name,\n languages,\n frameworks,\n subprojects,\n tools: confirmed,\n warnings,\n scan_metadata,\n };\n}\n\nfunction primaryManifestForEcosystem(ecosystem: Ecosystem): string {\n switch (ecosystem) {\n case 'npm':\n return 'package.json';\n case 'pypi':\n return 'pyproject.toml';\n case 'cargo':\n return 'Cargo.toml';\n case 'go':\n return 'go.mod';\n case 'rubygems':\n return 'Gemfile';\n case 'maven':\n return 'pom.xml';\n case 'gradle':\n return 'build.gradle';\n case 'composer':\n return 'composer.json';\n case 'hex':\n return 'mix.exs';\n case 'pub':\n return 'pubspec.yaml';\n case 'nuget':\n return '*.csproj';\n case 'swift-pm':\n return 'Package.swift';\n }\n}\n\nasync function inferProjectName(projectRoot: string): Promise<string> {\n // Prefer package.json#name, then Cargo.toml [package].name, then pyproject.toml [project].name.\n const pkgPath = resolve(projectRoot, 'package.json');\n if (await fileExists(pkgPath)) {\n try {\n const doc = JSON.parse(await readFile(pkgPath, 'utf-8')) as { name?: string };\n if (doc.name) return doc.name;\n } catch {\n /* non-fatal */\n }\n }\n return basename(projectRoot);\n}\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Ecosystem } from '@toolcairn/types';\nimport { fileExists } from './util/fs.js';\n\n/** Manifest presence → ecosystem. Lockfile or manifest either triggers detection. */\nconst ECOSYSTEM_MANIFESTS: Record<Ecosystem, string[]> = {\n npm: ['package.json'],\n pypi: ['pyproject.toml', 'requirements.txt', 'requirements-dev.txt', 'setup.py', 'Pipfile'],\n cargo: ['Cargo.toml'],\n go: ['go.mod'],\n rubygems: ['Gemfile'],\n maven: ['pom.xml'],\n gradle: ['build.gradle', 'build.gradle.kts', 'gradle.lockfile'],\n composer: ['composer.json'],\n hex: ['mix.exs'],\n pub: ['pubspec.yaml'],\n nuget: ['packages.config'],\n 'swift-pm': ['Package.swift'],\n};\n\n/** Any file extension that pattern-matches an ecosystem (e.g. *.csproj for nuget). */\nconst ECOSYSTEM_EXTENSIONS: Record<string, Ecosystem> = {\n '.csproj': 'nuget',\n '.fsproj': 'nuget',\n};\n\n/**\n * Detect which ecosystems have manifests in the given directory.\n * Does not recurse — caller invokes per workspace.\n */\nexport async function detectEcosystems(workspaceDir: string): Promise<Ecosystem[]> {\n const found = new Set<Ecosystem>();\n\n // Check well-known filenames\n for (const [ecosystem, files] of Object.entries(ECOSYSTEM_MANIFESTS) as Array<\n [Ecosystem, string[]]\n >) {\n for (const file of files) {\n if (await fileExists(join(workspaceDir, file))) {\n found.add(ecosystem);\n break;\n }\n }\n }\n\n // Check extension patterns (e.g. *.csproj)\n try {\n const entries = await readdir(workspaceDir);\n for (const entry of entries) {\n for (const [ext, ecosystem] of Object.entries(ECOSYSTEM_EXTENSIONS)) {\n if (entry.endsWith(ext)) {\n found.add(ecosystem);\n break;\n }\n }\n }\n } catch {\n // unreadable dir — skip\n }\n\n return Array.from(found);\n}\n","import type { Ecosystem, ProjectFramework } from '@toolcairn/types';\nimport type { DetectedTool } from '../types.js';\n\n/**\n * Offline framework-detection map — primary signal is the engine batch-resolve\n * `categories` array; this is the fallback for tools not in the graph, or when\n * the engine is unreachable.\n */\nconst FALLBACK: Record<Ecosystem, Record<string, string>> = {\n npm: {\n next: 'Next.js',\n react: 'React',\n vue: 'Vue',\n nuxt: 'Nuxt',\n svelte: 'Svelte',\n '@sveltejs/kit': 'SvelteKit',\n astro: 'Astro',\n 'solid-js': 'SolidJS',\n express: 'Express',\n fastify: 'Fastify',\n koa: 'Koa',\n hono: 'Hono',\n '@nestjs/core': 'NestJS',\n remix: 'Remix',\n '@remix-run/react': 'Remix',\n gatsby: 'Gatsby',\n electron: 'Electron',\n 'react-native': 'React Native',\n expo: 'Expo',\n angular: 'Angular',\n '@angular/core': 'Angular',\n turbo: 'Turborepo',\n nx: 'Nx',\n vite: 'Vite',\n webpack: 'Webpack',\n },\n pypi: {\n django: 'Django',\n flask: 'Flask',\n fastapi: 'FastAPI',\n starlette: 'Starlette',\n pyramid: 'Pyramid',\n tornado: 'Tornado',\n aiohttp: 'aiohttp',\n litestar: 'Litestar',\n sanic: 'Sanic',\n bottle: 'Bottle',\n quart: 'Quart',\n celery: 'Celery',\n streamlit: 'Streamlit',\n gradio: 'Gradio',\n torch: 'PyTorch',\n tensorflow: 'TensorFlow',\n transformers: 'Transformers',\n langchain: 'LangChain',\n 'llama-index': 'LlamaIndex',\n },\n cargo: {\n 'actix-web': 'Actix Web',\n axum: 'Axum',\n rocket: 'Rocket',\n warp: 'Warp',\n tide: 'Tide',\n poem: 'Poem',\n salvo: 'Salvo',\n leptos: 'Leptos',\n dioxus: 'Dioxus',\n yew: 'Yew',\n tauri: 'Tauri',\n bevy: 'Bevy',\n tokio: 'Tokio',\n },\n go: {\n 'github.com/gin-gonic/gin': 'Gin',\n 'github.com/labstack/echo': 'Echo',\n 'github.com/labstack/echo/v4': 'Echo',\n 'github.com/gofiber/fiber': 'Fiber',\n 'github.com/gofiber/fiber/v2': 'Fiber',\n 'github.com/beego/beego': 'Beego',\n 'github.com/go-chi/chi': 'Chi',\n 'github.com/gorilla/mux': 'Gorilla',\n 'github.com/revel/revel': 'Revel',\n },\n rubygems: {\n rails: 'Ruby on Rails',\n sinatra: 'Sinatra',\n hanami: 'Hanami',\n roda: 'Roda',\n rack: 'Rack',\n },\n maven: {\n 'org.springframework.boot:spring-boot-starter': 'Spring Boot',\n 'org.springframework.boot:spring-boot-starter-web': 'Spring Boot',\n 'io.quarkus:quarkus-core': 'Quarkus',\n 'io.micronaut:micronaut-core': 'Micronaut',\n 'io.vertx:vertx-core': 'Vert.x',\n 'com.google.inject:guice': 'Guice',\n },\n gradle: {\n 'org.springframework.boot:spring-boot-starter': 'Spring Boot',\n 'io.quarkus:quarkus-core': 'Quarkus',\n 'io.micronaut:micronaut-core': 'Micronaut',\n 'io.ktor:ktor-server-core': 'Ktor',\n },\n composer: {\n 'laravel/framework': 'Laravel',\n 'symfony/framework-bundle': 'Symfony',\n 'cakephp/cakephp': 'CakePHP',\n 'yiisoft/yii2': 'Yii',\n 'slim/slim': 'Slim',\n },\n hex: {\n phoenix: 'Phoenix',\n ecto: 'Ecto',\n nerves: 'Nerves',\n ash: 'Ash',\n },\n pub: {\n flutter: 'Flutter',\n flutter_bloc: 'Flutter BLoC',\n },\n nuget: {\n 'Microsoft.AspNetCore.App': 'ASP.NET Core',\n 'Microsoft.AspNetCore': 'ASP.NET Core',\n 'Microsoft.EntityFrameworkCore': 'Entity Framework Core',\n 'Microsoft.NET.Sdk.Web': 'ASP.NET Core',\n Avalonia: 'Avalonia',\n MAUI: '.NET MAUI',\n },\n 'swift-pm': {\n vapor: 'Vapor',\n kitura: 'Kitura',\n perfect: 'Perfect',\n },\n};\n\n/** Categories that indicate \"this IS a framework\" when returned by batch-resolve. */\nconst FRAMEWORK_CATEGORIES = new Set([\n 'framework',\n 'web-framework',\n 'ui-framework',\n 'meta-framework',\n 'backend-framework',\n 'frontend-framework',\n 'mobile-framework',\n]);\n\nexport interface BatchResolveResult {\n input: { name: string; ecosystem: Ecosystem };\n matched: boolean;\n tool?: { canonical_name: string; categories: string[] };\n}\n\n/**\n * Build the frameworks[] array for config.json.\n *\n * Primary signal: batch-resolve response carries a `categories` array with a\n * framework-like tag — use graph-resolved canonical name and tag source='graph'.\n * Fallback (offline or non-indexed): check FALLBACK[ecosystem][name] and tag\n * source='local'.\n *\n * De-duplicates by (framework_name, workspace). Dev-dependencies are ignored\n * (a dev-dep is almost never \"the framework\").\n */\nexport function detectFrameworks(\n tools: DetectedTool[],\n resolved: Map<string, BatchResolveResult>,\n): ProjectFramework[] {\n const out: ProjectFramework[] = [];\n const seen = new Set<string>();\n\n for (const tool of tools) {\n if (tool.section === 'dev') continue;\n const workspace = tool.workspace_path || '.';\n const resolvedKey = `${tool.ecosystem}:${tool.name}`;\n const graphMatch = resolved.get(resolvedKey);\n\n let frameworkName: string | null = null;\n let source: 'graph' | 'local' = 'local';\n\n if (graphMatch?.matched && graphMatch.tool) {\n const categories = graphMatch.tool.categories ?? [];\n if (categories.some((c) => FRAMEWORK_CATEGORIES.has(c.toLowerCase()))) {\n frameworkName = graphMatch.tool.canonical_name;\n source = 'graph';\n }\n }\n\n if (!frameworkName) {\n const localName = FALLBACK[tool.ecosystem]?.[tool.name];\n if (localName) {\n frameworkName = localName;\n source = 'local';\n }\n }\n\n if (!frameworkName) continue;\n const dedupeKey = `${frameworkName}:${workspace}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n\n out.push({\n name: frameworkName,\n ecosystem: tool.ecosystem,\n workspace,\n source,\n });\n }\n\n return out;\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport type { ProjectLanguage } from '@toolcairn/types';\nimport { IGNORED_DIRS } from './util/fs.js';\n\n/** File extension → language name. Only extensions with clear 1:1 mapping. */\nconst EXT_TO_LANGUAGE: Record<string, string> = {\n '.ts': 'TypeScript',\n '.tsx': 'TypeScript',\n '.js': 'JavaScript',\n '.jsx': 'JavaScript',\n '.mjs': 'JavaScript',\n '.cjs': 'JavaScript',\n '.py': 'Python',\n '.pyi': 'Python',\n '.rs': 'Rust',\n '.go': 'Go',\n '.rb': 'Ruby',\n '.java': 'Java',\n '.kt': 'Kotlin',\n '.kts': 'Kotlin',\n '.scala': 'Scala',\n '.php': 'PHP',\n '.ex': 'Elixir',\n '.exs': 'Elixir',\n '.erl': 'Erlang',\n '.dart': 'Dart',\n '.cs': 'C#',\n '.fs': 'F#',\n '.vb': 'Visual Basic',\n '.swift': 'Swift',\n '.c': 'C',\n '.h': 'C',\n '.cpp': 'C++',\n '.cxx': 'C++',\n '.cc': 'C++',\n '.hpp': 'C++',\n '.m': 'Objective-C',\n '.mm': 'Objective-C',\n '.lua': 'Lua',\n '.r': 'R',\n '.jl': 'Julia',\n '.nim': 'Nim',\n '.zig': 'Zig',\n '.clj': 'Clojure',\n '.cljs': 'Clojure',\n '.hs': 'Haskell',\n '.elm': 'Elm',\n '.ml': 'OCaml',\n '.mli': 'OCaml',\n '.vue': 'Vue',\n '.svelte': 'Svelte',\n '.astro': 'Astro',\n};\n\n/**\n * Walk the tree once, counting files per language globally and per workspace.\n * A workspace is any directory passed in `workspaceRels` (relative, POSIX-normalised).\n * Root workspace is represented as \"\" and always included.\n *\n * The walker skips IGNORED_DIRS (node_modules, target, dist, etc.) — a file inside\n * node_modules is never counted.\n */\nexport async function detectLanguages(\n projectRoot: string,\n workspaceRels: string[],\n): Promise<ProjectLanguage[]> {\n const globalCounts = new Map<string, number>();\n const perWorkspace = new Map<string, Map<string, number>>(); // workspace_rel → lang → count\n\n // Sort workspace rels longest-first so deeper workspaces claim their files before parents.\n const sortedRels = [...workspaceRels, '']\n .filter((v, i, arr) => arr.indexOf(v) === i)\n .sort((a, b) => b.length - a.length);\n for (const rel of sortedRels) perWorkspace.set(rel, new Map());\n\n await walk(projectRoot, projectRoot, globalCounts, perWorkspace, sortedRels);\n\n return [...globalCounts.entries()]\n .map(([name, file_count]) => {\n const workspaces = sortedRels\n .filter((rel) => (perWorkspace.get(rel)?.get(name) ?? 0) > 0)\n .map((rel) => rel || '.');\n return { name, file_count, workspaces };\n })\n .filter((l) => l.file_count > 0)\n .sort((a, b) => b.file_count - a.file_count);\n}\n\nasync function walk(\n root: string,\n dir: string,\n global: Map<string, number>,\n perWorkspace: Map<string, Map<string, number>>,\n workspaceRels: string[],\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.github') {\n if (!['.toolcairn', '.claude'].includes(entry.name)) continue;\n }\n if (IGNORED_DIRS.has(entry.name)) continue;\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(root, full, global, perWorkspace, workspaceRels);\n } else if (entry.isFile()) {\n const ext = pickExtension(entry.name);\n if (!ext) continue;\n const lang = EXT_TO_LANGUAGE[ext];\n if (!lang) continue;\n global.set(lang, (global.get(lang) ?? 0) + 1);\n // Find the deepest workspace that owns this file\n const relFile = relative(root, full).split(sep).join('/');\n for (const wsRel of workspaceRels) {\n if (wsRel === '' || relFile === wsRel || relFile.startsWith(`${wsRel}/`)) {\n const m = perWorkspace.get(wsRel);\n if (m) m.set(lang, (m.get(lang) ?? 0) + 1);\n break;\n }\n }\n }\n }\n}\n\nfunction pickExtension(filename: string): string | null {\n const idx = filename.lastIndexOf('.');\n if (idx < 0 || idx === 0) return null;\n return filename.slice(idx).toLowerCase();\n}\n","import type { Ecosystem } from '@toolcairn/types';\nimport type { Parser } from '../types.js';\nimport { parseCargo } from './cargo.js';\nimport { parseComposer } from './composer.js';\nimport { parseDart } from './dart.js';\nimport { parseDotnet } from './dotnet.js';\nimport { parseGo } from './go.js';\nimport { parseGradle } from './gradle.js';\nimport { parseMaven } from './maven.js';\nimport { parseMix } from './mix.js';\nimport { parseNpm } from './npm.js';\nimport { parsePypi } from './pypi.js';\nimport { parseRuby } from './ruby.js';\nimport { parseSwift } from './swift.js';\n\nexport const PARSERS: Record<Ecosystem, Parser> = {\n npm: parseNpm,\n pypi: parsePypi,\n cargo: parseCargo,\n go: parseGo,\n rubygems: parseRuby,\n maven: parseMaven,\n gradle: parseGradle,\n composer: parseComposer,\n hex: parseMix,\n pub: parseDart,\n nuget: parseDotnet,\n 'swift-pm': parseSwift,\n};\n\nexport {\n parseCargo,\n parseComposer,\n parseDart,\n parseDotnet,\n parseGo,\n parseGradle,\n parseMaven,\n parseMix,\n parseNpm,\n parsePypi,\n parseRuby,\n parseSwift,\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseToml } from 'smol-toml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface CargoToml {\n package?: { name?: string };\n dependencies?: Record<string, string | { version?: string }>;\n 'dev-dependencies'?: Record<string, string | { version?: string }>;\n 'build-dependencies'?: Record<string, string | { version?: string }>;\n workspace?: {\n dependencies?: Record<string, string | { version?: string }>;\n members?: string[];\n };\n}\n\ninterface CargoLock {\n package?: Array<{ name?: string; version?: string }>;\n}\n\nconst SECTION_MAP: Array<[keyof CargoToml, ManifestSection]> = [\n ['dependencies', 'dep'],\n ['dev-dependencies', 'dev'],\n ['build-dependencies', 'build'],\n];\n\nfunction extractDeps(\n obj: Record<string, string | { version?: string }> | undefined,\n section: ManifestSection,\n resolved: Map<string, string>,\n out: ParseResult['tools'],\n manifestFile: string,\n workspaceRel: string,\n): void {\n if (!obj) return;\n for (const [name, value] of Object.entries(obj)) {\n const constraint = typeof value === 'string' ? value : value.version;\n out.push({\n name,\n ecosystem: 'cargo',\n version_constraint: constraint,\n resolved_version: resolved.get(name),\n section,\n manifest_file: manifestFile,\n workspace_path: workspaceRel,\n });\n }\n}\n\nexport const parseCargo: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const manifestPath = join(workspace_dir, 'Cargo.toml');\n if (!(await fileExists(manifestPath))) return { ecosystem: 'cargo', tools, warnings };\n\n let manifest: CargoToml;\n try {\n manifest = parseToml(await readFile(manifestPath, 'utf-8')) as CargoToml;\n } catch (err) {\n warnings.push({\n scope: 'parser:cargo',\n path: manifestPath,\n message: `Failed to parse Cargo.toml: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'cargo', tools, warnings };\n }\n\n const resolved = new Map<string, string>();\n const lockPath = join(workspace_dir, 'Cargo.lock');\n if (await fileExists(lockPath)) {\n try {\n const lock = parseToml(await readFile(lockPath, 'utf-8')) as CargoLock;\n for (const pkg of lock.package ?? []) {\n if (pkg.name && pkg.version) resolved.set(pkg.name, pkg.version);\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:cargo',\n path: lockPath,\n message: `Failed to parse Cargo.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/Cargo.toml` : 'Cargo.toml';\n\n for (const [field, section] of SECTION_MAP) {\n extractDeps(\n manifest[field] as Record<string, string | { version?: string }> | undefined,\n section,\n resolved,\n tools,\n manifestFile,\n workspace_rel,\n );\n }\n\n // Workspace-level dependencies (shared across members)\n extractDeps(\n manifest.workspace?.dependencies,\n 'dep',\n resolved,\n tools,\n manifestFile,\n workspace_rel,\n );\n\n return { ecosystem: 'cargo', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface ComposerJson {\n require?: Record<string, string>;\n 'require-dev'?: Record<string, string>;\n}\n\ninterface ComposerLockPackage {\n name?: string;\n version?: string;\n}\n\ninterface ComposerLock {\n packages?: ComposerLockPackage[];\n 'packages-dev'?: ComposerLockPackage[];\n}\n\n/** Skips PHP platform pseudo-packages that aren't real deps. */\nfunction isPhpPlatform(name: string): boolean {\n return name === 'php' || name.startsWith('ext-') || name.startsWith('lib-');\n}\n\nexport const parseComposer: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'composer.lock');\n const manifestPath = join(workspace_dir, 'composer.json');\n\n // Prefer lockfile\n if (await fileExists(lockPath)) {\n try {\n const lock = JSON.parse(await readFile(lockPath, 'utf-8')) as ComposerLock;\n const manifestFile = workspace_rel ? `${workspace_rel}/composer.lock` : 'composer.lock';\n for (const [pkgs, section] of [\n [lock.packages ?? [], 'dep'] as const,\n [lock['packages-dev'] ?? [], 'dev'] as const,\n ]) {\n for (const pkg of pkgs) {\n if (!pkg.name || isPhpPlatform(pkg.name)) continue;\n tools.push({\n name: pkg.name,\n ecosystem: 'composer',\n version_constraint: undefined,\n resolved_version: pkg.version,\n section: section as ManifestSection,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n if (tools.length > 0) return { ecosystem: 'composer', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:composer',\n path: lockPath,\n message: `Failed to parse composer.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: composer.json\n if (await fileExists(manifestPath)) {\n try {\n const manifest = JSON.parse(await readFile(manifestPath, 'utf-8')) as ComposerJson;\n const manifestFile = workspace_rel ? `${workspace_rel}/composer.json` : 'composer.json';\n for (const [obj, section] of [\n [manifest.require, 'dep'] as const,\n [manifest['require-dev'], 'dev'] as const,\n ]) {\n for (const [name, constraint] of Object.entries(obj ?? {})) {\n if (isPhpPlatform(name)) continue;\n tools.push({\n name,\n ecosystem: 'composer',\n version_constraint: constraint,\n section: section as ManifestSection,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:composer',\n path: manifestPath,\n message: `Failed to parse composer.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'composer', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseYaml } from 'yaml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface Pubspec {\n name?: string;\n dependencies?: Record<string, string | { version?: string; sdk?: string; path?: string }>;\n dev_dependencies?: Record<string, string | { version?: string; sdk?: string; path?: string }>;\n}\n\ninterface PubspecLockPackage {\n version?: string;\n dependency?: string;\n}\n\ninterface PubspecLock {\n packages?: Record<string, PubspecLockPackage>;\n}\n\nfunction isSkippableDep(value: unknown): boolean {\n if (typeof value === 'object' && value !== null) {\n const v = value as { sdk?: string; path?: string };\n if (v.sdk || v.path) return true;\n }\n return false;\n}\n\nfunction extractDeps(\n obj: Pubspec['dependencies'],\n section: ManifestSection,\n resolved: Map<string, string>,\n out: ParseResult['tools'],\n manifestFile: string,\n workspaceRel: string,\n): void {\n if (!obj) return;\n for (const [name, value] of Object.entries(obj)) {\n if (isSkippableDep(value)) continue;\n const constraint = typeof value === 'string' ? value : value.version;\n out.push({\n name,\n ecosystem: 'pub',\n version_constraint: constraint,\n resolved_version: resolved.get(name),\n section,\n manifest_file: manifestFile,\n workspace_path: workspaceRel,\n });\n }\n}\n\nexport const parseDart: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const pubspecPath = join(workspace_dir, 'pubspec.yaml');\n if (!(await fileExists(pubspecPath))) return { ecosystem: 'pub', tools, warnings };\n\n let pubspec: Pubspec;\n try {\n pubspec = parseYaml(await readFile(pubspecPath, 'utf-8')) as Pubspec;\n } catch (err) {\n warnings.push({\n scope: 'parser:dart',\n path: pubspecPath,\n message: `Failed to parse pubspec.yaml: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'pub', tools, warnings };\n }\n\n const resolved = new Map<string, string>();\n const lockPath = join(workspace_dir, 'pubspec.lock');\n if (await fileExists(lockPath)) {\n try {\n const lock = parseYaml(await readFile(lockPath, 'utf-8')) as PubspecLock;\n for (const [name, pkg] of Object.entries(lock.packages ?? {})) {\n if (pkg.version) resolved.set(name, pkg.version);\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:dart',\n path: lockPath,\n message: `Failed to parse pubspec.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/pubspec.yaml` : 'pubspec.yaml';\n extractDeps(pubspec.dependencies, 'dep', resolved, tools, manifestFile, workspace_rel);\n extractDeps(pubspec.dev_dependencies, 'dev', resolved, tools, manifestFile, workspace_rel);\n\n return { ecosystem: 'pub', tools, warnings };\n};\n","import { readFile, readdir } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport { XMLParser } from 'fast-xml-parser';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PackageRef {\n '@_Include'?: string;\n '@_Version'?: string;\n '@_PrivateAssets'?: string;\n}\n\ninterface CsProj {\n Project?: {\n ItemGroup?:\n | { PackageReference?: PackageRef | PackageRef[] }\n | Array<{ PackageReference?: PackageRef | PackageRef[] }>;\n };\n}\n\ninterface PackagesConfig {\n packages?: {\n package?: PackageRef | PackageRef[];\n };\n}\n\nfunction toArray<T>(v: T | T[] | undefined): T[] {\n if (v === undefined) return [];\n return Array.isArray(v) ? v : [v];\n}\n\nexport const parseDotnet: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n let entries: string[] = [];\n try {\n entries = await readdir(workspace_dir);\n } catch {\n return { ecosystem: 'nuget', tools, warnings };\n }\n\n const csprojFiles = entries.filter((f) => f.endsWith('.csproj') || f.endsWith('.fsproj'));\n const xmlParser = new XMLParser({ ignoreAttributes: false });\n\n for (const proj of csprojFiles) {\n const path = join(workspace_dir, proj);\n try {\n const raw = await readFile(path, 'utf-8');\n const doc = xmlParser.parse(raw) as CsProj;\n const itemGroups = Array.isArray(doc.Project?.ItemGroup)\n ? (doc.Project?.ItemGroup ?? [])\n : doc.Project?.ItemGroup\n ? [doc.Project.ItemGroup]\n : [];\n const manifestFile = workspace_rel\n ? `${workspace_rel}/${relative(workspace_dir, path)}`\n : relative(workspace_dir, path);\n for (const group of itemGroups) {\n for (const ref of toArray(group.PackageReference)) {\n const name = ref['@_Include'];\n if (!name) continue;\n const version = ref['@_Version'];\n tools.push({\n name,\n ecosystem: 'nuget',\n version_constraint: version,\n resolved_version: version,\n section: ref['@_PrivateAssets'] ? 'build' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:dotnet',\n path,\n message: `Failed to parse ${proj}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Legacy packages.config (full framework)\n const pkgConfigPath = join(workspace_dir, 'packages.config');\n if (await fileExists(pkgConfigPath)) {\n try {\n const raw = await readFile(pkgConfigPath, 'utf-8');\n const doc = xmlParser.parse(raw) as PackagesConfig;\n const manifestFile = workspace_rel ? `${workspace_rel}/packages.config` : 'packages.config';\n for (const pkg of toArray(doc.packages?.package)) {\n const name = pkg['@_Include'];\n if (!name) continue;\n tools.push({\n name,\n ecosystem: 'nuget',\n version_constraint: pkg['@_Version'],\n resolved_version: pkg['@_Version'],\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:dotnet',\n path: pkgConfigPath,\n message: `Failed to parse packages.config: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'nuget', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/**\n * Parses go.mod — line-oriented format:\n * require (\n * github.com/foo/bar v1.2.3\n * github.com/baz/qux v0.5.1 // indirect\n * )\n * Or single-line: require github.com/foo/bar v1.2.3\n */\nfunction parseGoMod(raw: string): Array<{ name: string; version: string; indirect: boolean }> {\n const out: Array<{ name: string; version: string; indirect: boolean }> = [];\n const lines = raw.split('\\n');\n let inRequireBlock = false;\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\/\\/.*$/, '').trim();\n const commentTail = rawLine.match(/\\/\\/\\s*(.*)$/)?.[1] ?? '';\n const indirect = /\\bindirect\\b/.test(commentTail);\n if (!line) continue;\n if (line === 'require (') {\n inRequireBlock = true;\n continue;\n }\n if (line === ')') {\n inRequireBlock = false;\n continue;\n }\n if (line.startsWith('require ')) {\n // single-line require github.com/x v1.0.0\n const parts = line.slice(8).trim().split(/\\s+/);\n if (parts[0] && parts[1]) out.push({ name: parts[0], version: parts[1], indirect });\n continue;\n }\n if (inRequireBlock) {\n const parts = line.split(/\\s+/);\n if (parts[0] && parts[1]) out.push({ name: parts[0], version: parts[1], indirect });\n }\n }\n return out;\n}\n\nexport const parseGo: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const modPath = join(workspace_dir, 'go.mod');\n if (!(await fileExists(modPath))) return { ecosystem: 'go', tools, warnings };\n\n try {\n const raw = await readFile(modPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/go.mod` : 'go.mod';\n for (const dep of parseGoMod(raw)) {\n tools.push({\n name: dep.name,\n ecosystem: 'go',\n version_constraint: dep.version,\n resolved_version: dep.version, // go.mod pins exact version\n section: dep.indirect ? 'optional' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:go',\n path: modPath,\n message: `Failed to parse go.mod: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n return { ecosystem: 'go', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/** gradle.lockfile is deterministic: one line per dep as \"group:name:version=configurations\". */\nfunction parseGradleLockfile(\n raw: string,\n): Array<{ group: string; name: string; version: string; configurations: string[] }> {\n const out: Array<{ group: string; name: string; version: string; configurations: string[] }> = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const match = trimmed.match(/^([^:]+):([^:]+):([^=]+)=(.*)$/);\n if (match?.[1] && match[2] && match[3]) {\n out.push({\n group: match[1],\n name: match[2],\n version: match[3],\n configurations: (match[4] ?? '').split(',').map((s) => s.trim()),\n });\n }\n }\n return out;\n}\n\nfunction gradleConfigToSection(configs: string[]): ManifestSection {\n const joined = configs.join(' ').toLowerCase();\n if (joined.includes('test')) return 'dev';\n if (joined.includes('annotationprocessor') || joined.includes('kapt')) return 'build';\n return 'dep';\n}\n\n/** Shallow build.gradle(.kts) regex scan: `implementation \"group:name:version\"`. */\nfunction parseBuildGradle(raw: string): Array<{ spec: string; config: string }> {\n const out: Array<{ spec: string; config: string }> = [];\n // Groovy: implementation 'group:name:version'\n // Kotlin: implementation(\"group:name:version\")\n const patterns = [\n /(implementation|api|compileOnly|runtimeOnly|testImplementation|testRuntimeOnly|annotationProcessor|kapt|ksp)\\s*\\(?\\s*(['\"])([A-Za-z0-9_.\\-]+:[A-Za-z0-9_.\\-]+:[^'\"]+)\\2/g,\n ];\n for (const pattern of patterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n if (match[1] && match[3]) out.push({ spec: match[3], config: match[1] });\n }\n }\n return out;\n}\n\nfunction configKeywordToSection(config: string): ManifestSection {\n const c = config.toLowerCase();\n if (c.startsWith('test')) return 'dev';\n if (c.includes('annotationprocessor') || c === 'kapt' || c === 'ksp') return 'build';\n return 'dep';\n}\n\nexport const parseGradle: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'gradle.lockfile');\n if (await fileExists(lockPath)) {\n try {\n const raw = await readFile(lockPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/gradle.lockfile` : 'gradle.lockfile';\n for (const dep of parseGradleLockfile(raw)) {\n tools.push({\n name: `${dep.group}:${dep.name}`,\n ecosystem: 'gradle',\n version_constraint: dep.version,\n resolved_version: dep.version,\n section: gradleConfigToSection(dep.configurations),\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'gradle', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:gradle',\n path: lockPath,\n message: `Failed to parse gradle.lockfile: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: shallow regex scan of build.gradle / build.gradle.kts\n for (const filename of ['build.gradle.kts', 'build.gradle']) {\n const path = join(workspace_dir, filename);\n if (!(await fileExists(path))) continue;\n try {\n const raw = await readFile(path, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/${filename}` : filename;\n let hasVariable = false;\n for (const dep of parseBuildGradle(raw)) {\n const parts = dep.spec.split(':');\n if (parts.length < 3 || !parts[0] || !parts[1]) continue;\n const version = parts.slice(2).join(':');\n if (version.startsWith('$') || version.includes('${')) {\n hasVariable = true;\n continue;\n }\n tools.push({\n name: `${parts[0]}:${parts[1]}`,\n ecosystem: 'gradle',\n version_constraint: version,\n section: configKeywordToSection(dep.config),\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n warnings.push({\n scope: 'parser:gradle',\n path: manifestFile,\n message:\n 'Shallow parse of build.gradle — results may be incomplete. Add `dependencyLocking` to the project for deterministic discovery.',\n });\n if (hasVariable) {\n warnings.push({\n scope: 'parser:gradle',\n path: manifestFile,\n message: 'Some deps use variable interpolation ($ver / ${var}) — skipped.',\n });\n }\n break;\n } catch (err) {\n warnings.push({\n scope: 'parser:gradle',\n path,\n message: `Failed to read ${filename}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'gradle', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { XMLParser } from 'fast-xml-parser';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface MavenDep {\n groupId?: string;\n artifactId?: string;\n version?: string;\n scope?: string;\n optional?: string | boolean;\n}\n\ninterface MavenPom {\n project?: {\n dependencies?: { dependency?: MavenDep | MavenDep[] };\n dependencyManagement?: { dependencies?: { dependency?: MavenDep | MavenDep[] } };\n };\n}\n\nfunction scopeToSection(scope: string | undefined, optional: boolean): ManifestSection {\n if (optional) return 'optional';\n switch (scope) {\n case 'test':\n case 'provided':\n return 'dev';\n default:\n return 'dep';\n }\n}\n\nfunction toArray<T>(v: T | T[] | undefined): T[] {\n if (v === undefined) return [];\n return Array.isArray(v) ? v : [v];\n}\n\nexport const parseMaven: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const pomPath = join(workspace_dir, 'pom.xml');\n if (!(await fileExists(pomPath))) return { ecosystem: 'maven', tools, warnings };\n\n let doc: MavenPom;\n try {\n const raw = await readFile(pomPath, 'utf-8');\n const parser = new XMLParser({ ignoreAttributes: true, parseTagValue: true });\n doc = parser.parse(raw) as MavenPom;\n } catch (err) {\n warnings.push({\n scope: 'parser:maven',\n path: pomPath,\n message: `Failed to parse pom.xml: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'maven', tools, warnings };\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/pom.xml` : 'pom.xml';\n const deps = toArray(doc.project?.dependencies?.dependency);\n const managedDeps = toArray(doc.project?.dependencyManagement?.dependencies?.dependency);\n let hasUnresolvedVariable = false;\n\n for (const dep of [...deps, ...managedDeps]) {\n if (!dep.groupId || !dep.artifactId) continue;\n const name = `${dep.groupId}:${dep.artifactId}`;\n const version = typeof dep.version === 'string' ? dep.version : undefined;\n if (version && version.includes('${')) hasUnresolvedVariable = true;\n const optional = dep.optional === true || dep.optional === 'true';\n tools.push({\n name,\n ecosystem: 'maven',\n version_constraint: version,\n resolved_version: version && !version.includes('${') ? version : undefined,\n section: scopeToSection(dep.scope, optional),\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n\n if (hasUnresolvedVariable) {\n warnings.push({\n scope: 'parser:maven',\n path: pomPath,\n message:\n 'Some dependencies use ${...} variable interpolation which is not resolved — version info may be incomplete.',\n });\n }\n\n return { ecosystem: 'maven', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/**\n * mix.lock format (Elixir):\n * %{\n * \"phoenix\": {:hex, :phoenix, \"1.7.10\", \"hash\", [...], [...]},\n * \"ecto\": {:hex, :ecto, \"3.11.0\", \"hash\", [...]}\n * }\n *\n * We just need name + version — extract via regex.\n */\nfunction parseMixLock(raw: string): Array<{ name: string; version: string }> {\n const out: Array<{ name: string; version: string }> = [];\n const pattern = /\"([^\"]+)\":\\s*\\{\\s*:hex\\s*,\\s*:[A-Za-z_][A-Za-z0-9_]*\\s*,\\s*\"([^\"]+)\"/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n if (match[1] && match[2]) out.push({ name: match[1], version: match[2] });\n }\n return out;\n}\n\n/**\n * mix.exs deps/0 block (fallback if no mix.lock):\n * defp deps do\n * [\n * {:phoenix, \"~> 1.7\"},\n * {:ecto, \"~> 3.11\", only: [:dev]}\n * ]\n * end\n */\nfunction parseMixExs(raw: string): Array<{ name: string; constraint?: string; dev: boolean }> {\n const out: Array<{ name: string; constraint?: string; dev: boolean }> = [];\n const pattern =\n /\\{:([a-z_][a-z0-9_]*)\\s*,\\s*\"([^\"]+)\"(?:[^}]*only:\\s*(?:\\[?:?([a-z_]+))?[^}]*)?\\}/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n if (match[1]) {\n const onlyScope = match[3];\n out.push({\n name: match[1],\n constraint: match[2],\n dev: onlyScope === 'dev' || onlyScope === 'test',\n });\n }\n }\n return out;\n}\n\nexport const parseMix: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'mix.lock');\n if (await fileExists(lockPath)) {\n try {\n const raw = await readFile(lockPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/mix.lock` : 'mix.lock';\n for (const dep of parseMixLock(raw)) {\n tools.push({\n name: dep.name,\n ecosystem: 'hex',\n version_constraint: undefined,\n resolved_version: dep.version,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'hex', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:mix',\n path: lockPath,\n message: `Failed to parse mix.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n const exsPath = join(workspace_dir, 'mix.exs');\n if (await fileExists(exsPath)) {\n try {\n const raw = await readFile(exsPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/mix.exs` : 'mix.exs';\n for (const dep of parseMixExs(raw)) {\n tools.push({\n name: dep.name,\n ecosystem: 'hex',\n version_constraint: dep.constraint,\n section: dep.dev ? 'dev' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:mix',\n path: exsPath,\n message: `Failed to parse mix.exs: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'hex', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseYaml } from 'yaml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n workspaces?: string[] | { packages?: string[] };\n}\n\ninterface PnpmLockPackage {\n version?: string;\n}\n\ninterface PnpmLock {\n importers?: Record<\n string,\n {\n dependencies?: Record<string, { version?: string } | string>;\n devDependencies?: Record<string, { version?: string } | string>;\n peerDependencies?: Record<string, { version?: string } | string>;\n optionalDependencies?: Record<string, { version?: string } | string>;\n }\n >;\n packages?: Record<string, PnpmLockPackage>;\n}\n\ninterface NpmLockDep {\n version?: string;\n resolved?: string;\n dev?: boolean;\n optional?: boolean;\n peer?: boolean;\n}\n\ninterface NpmLock {\n packages?: Record<string, NpmLockDep>;\n dependencies?: Record<string, NpmLockDep>;\n}\n\nconst SECTION_MAP: Array<[keyof PackageJson, ManifestSection]> = [\n ['dependencies', 'dep'],\n ['devDependencies', 'dev'],\n ['peerDependencies', 'peer'],\n ['optionalDependencies', 'optional'],\n];\n\n/** Extracts raw `X.Y.Z` version from a pnpm key like \"/@scope/name@1.2.3(peer@...)\". */\nfunction stripPnpmRange(raw: string): string | undefined {\n // pnpm v6/v7 entries in `packages` look like \"/react@18.2.0(peer@...)\".\n const atIdx = raw.lastIndexOf('@');\n if (atIdx <= 0) return undefined;\n const tail = raw.slice(atIdx + 1);\n const parenIdx = tail.indexOf('(');\n return parenIdx >= 0 ? tail.slice(0, parenIdx) : tail || undefined;\n}\n\n/** Resolves a dep's version from pnpm-lock importers + packages. */\nfunction resolvePnpmVersion(\n lock: PnpmLock,\n importerKey: string,\n section: 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies',\n depName: string,\n): string | undefined {\n const importer = lock.importers?.[importerKey];\n const entry = importer?.[section]?.[depName];\n if (!entry) return undefined;\n if (typeof entry === 'string') return entry;\n if (entry.version) {\n // pnpm v8+: version field contains the raw version; strip any \"(peer...)\" suffix\n const parenIdx = entry.version.indexOf('(');\n return parenIdx >= 0 ? entry.version.slice(0, parenIdx) : entry.version;\n }\n return undefined;\n}\n\n/** Resolves from package-lock.json (npm v7+ `packages` object keyed by \"node_modules/X\"). */\nfunction resolveNpmLockVersion(lock: NpmLock, depName: string): string | undefined {\n const key = `node_modules/${depName}`;\n return lock.packages?.[key]?.version ?? lock.dependencies?.[depName]?.version;\n}\n\nexport const parseNpm: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const manifestPath = join(workspace_dir, 'package.json');\n if (!(await fileExists(manifestPath))) {\n return { ecosystem: 'npm', tools, warnings };\n }\n\n let manifest: PackageJson;\n try {\n manifest = JSON.parse(await readFile(manifestPath, 'utf-8')) as PackageJson;\n } catch (err) {\n warnings.push({\n scope: 'parser:npm',\n path: manifestPath,\n message: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { ecosystem: 'npm', tools, warnings };\n }\n\n // Try to load a lockfile for resolved versions. Prefer pnpm > npm > yarn.\n let pnpmLock: PnpmLock | undefined;\n let npmLock: NpmLock | undefined;\n\n const pnpmLockPath = join(workspace_dir, 'pnpm-lock.yaml');\n const npmLockPath = join(workspace_dir, 'package-lock.json');\n\n if (await fileExists(pnpmLockPath)) {\n try {\n pnpmLock = parseYaml(await readFile(pnpmLockPath, 'utf-8')) as PnpmLock;\n } catch (err) {\n warnings.push({\n scope: 'parser:npm',\n path: pnpmLockPath,\n message: `Failed to parse pnpm-lock.yaml, falling back to manifest: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n } else if (await fileExists(npmLockPath)) {\n try {\n npmLock = JSON.parse(await readFile(npmLockPath, 'utf-8')) as NpmLock;\n } catch (err) {\n warnings.push({\n scope: 'parser:npm',\n path: npmLockPath,\n message: `Failed to parse package-lock.json, falling back to manifest: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n } else if (!(await fileExists(join(workspace_dir, 'yarn.lock')))) {\n warnings.push({\n scope: 'parser:npm',\n path: manifestPath,\n message: 'No lockfile present — resolved_version will be absent.',\n });\n }\n\n const manifestFile = workspace_rel ? `${workspace_rel}/package.json` : 'package.json';\n // In pnpm-lock, the root importer is \".\" and sub-workspaces use their relative paths.\n const pnpmImporterKey = workspace_rel || '.';\n\n for (const [field, section] of SECTION_MAP) {\n const deps = manifest[field] as Record<string, string> | undefined;\n if (!deps) continue;\n for (const [name, constraint] of Object.entries(deps)) {\n let resolved: string | undefined;\n if (pnpmLock) {\n resolved = resolvePnpmVersion(\n pnpmLock,\n pnpmImporterKey,\n field as Exclude<typeof field, 'workspaces' | 'name'>,\n name,\n );\n } else if (npmLock) {\n resolved = resolveNpmLockVersion(npmLock, name);\n }\n\n tools.push({\n name,\n ecosystem: 'npm',\n version_constraint: constraint,\n resolved_version: resolved,\n section,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n\n // Avoid unused-symbol warnings — stripPnpmRange is reserved for future \"packages\" fallback.\n void stripPnpmRange;\n\n return { ecosystem: 'npm', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning, ManifestSection } from '@toolcairn/types';\nimport { parse as parseToml } from 'smol-toml';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PyProject {\n project?: {\n name?: string;\n dependencies?: string[];\n 'optional-dependencies'?: Record<string, string[]>;\n };\n tool?: {\n poetry?: {\n name?: string;\n dependencies?: Record<string, string | { version?: string }>;\n 'dev-dependencies'?: Record<string, string | { version?: string }>;\n group?: Record<string, { dependencies?: Record<string, string | { version?: string }> }>;\n };\n uv?: {\n 'dev-dependencies'?: string[];\n };\n };\n 'dependency-groups'?: Record<string, string[]>;\n}\n\ninterface UvLockPackage {\n name?: string;\n version?: string;\n}\n\ninterface UvLock {\n package?: UvLockPackage[];\n}\n\n/** Parses \"fastapi>=0.100.0\" / \"django[argon2]<5\" into {name, constraint}. */\nfunction parseRequirementString(raw: string): { name: string; constraint?: string } | null {\n const trimmed = raw.trim();\n if (!trimmed || trimmed.startsWith('#')) return null;\n // Split on first of <, >, =, ~, !, [, ;, space\n const match = trimmed.match(/^([A-Za-z0-9_.\\-]+)(\\[[^\\]]*\\])?(.*)$/);\n if (!match || !match[1]) return null;\n const constraint = (match[3] ?? '').trim();\n return { name: match[1], constraint: constraint || undefined };\n}\n\nfunction addPoetryDeps(\n obj: Record<string, string | { version?: string }> | undefined,\n section: ManifestSection,\n out: ParseResult['tools'],\n manifestFile: string,\n workspaceRel: string,\n resolvedVersions: Map<string, string>,\n): void {\n if (!obj) return;\n for (const [name, value] of Object.entries(obj)) {\n if (name === 'python') continue; // Poetry's python interpreter pin\n const constraint = typeof value === 'string' ? value : value.version;\n out.push({\n name,\n ecosystem: 'pypi',\n version_constraint: constraint,\n resolved_version: resolvedVersions.get(name.toLowerCase()),\n section,\n manifest_file: manifestFile,\n workspace_path: workspaceRel,\n });\n }\n}\n\nexport const parsePypi: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n // Build resolved-version map from uv.lock if present.\n const resolved = new Map<string, string>();\n const uvLockPath = join(workspace_dir, 'uv.lock');\n if (await fileExists(uvLockPath)) {\n try {\n const lock = parseToml(await readFile(uvLockPath, 'utf-8')) as UvLock;\n for (const pkg of lock.package ?? []) {\n if (pkg.name && pkg.version) resolved.set(pkg.name.toLowerCase(), pkg.version);\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:pypi',\n path: uvLockPath,\n message: `Failed to parse uv.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // 1) pyproject.toml (strongest signal)\n const pyprojectPath = join(workspace_dir, 'pyproject.toml');\n if (await fileExists(pyprojectPath)) {\n try {\n const doc = parseToml(await readFile(pyprojectPath, 'utf-8')) as PyProject;\n const manifestFile = workspace_rel ? `${workspace_rel}/pyproject.toml` : 'pyproject.toml';\n\n // PEP 621 / uv style: [project].dependencies = [\"fastapi>=0.100\", ...]\n for (const dep of doc.project?.dependencies ?? []) {\n const parsed = parseRequirementString(dep);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n for (const [groupName, deps] of Object.entries(\n doc.project?.['optional-dependencies'] ?? {},\n )) {\n for (const dep of deps) {\n const parsed = parseRequirementString(dep);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section: groupName === 'dev' ? 'dev' : 'optional',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n\n // PEP 735 / uv style: [dependency-groups]\n for (const [groupName, deps] of Object.entries(doc['dependency-groups'] ?? {})) {\n for (const dep of deps) {\n const parsed = parseRequirementString(dep);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section: groupName === 'dev' ? 'dev' : 'optional',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n }\n\n // Poetry style: [tool.poetry.dependencies]\n addPoetryDeps(\n doc.tool?.poetry?.dependencies,\n 'dep',\n tools,\n manifestFile,\n workspace_rel,\n resolved,\n );\n addPoetryDeps(\n doc.tool?.poetry?.['dev-dependencies'],\n 'dev',\n tools,\n manifestFile,\n workspace_rel,\n resolved,\n );\n for (const group of Object.values(doc.tool?.poetry?.group ?? {})) {\n addPoetryDeps(group.dependencies, 'dev', tools, manifestFile, workspace_rel, resolved);\n }\n\n if (tools.length > 0) return { ecosystem: 'pypi', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:pypi',\n path: pyprojectPath,\n message: `Failed to parse pyproject.toml: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // 2) Fallback: requirements.txt (+ requirements-dev.txt)\n for (const [file, section] of [\n ['requirements.txt', 'dep'] as const,\n ['requirements-dev.txt', 'dev'] as const,\n ['dev-requirements.txt', 'dev'] as const,\n ]) {\n const path = join(workspace_dir, file);\n if (!(await fileExists(path))) continue;\n try {\n const raw = await readFile(path, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/${file}` : file;\n for (const line of raw.split('\\n')) {\n const parsed = parseRequirementString(line);\n if (!parsed) continue;\n tools.push({\n name: parsed.name,\n ecosystem: 'pypi',\n version_constraint: parsed.constraint,\n resolved_version: resolved.get(parsed.name.toLowerCase()),\n section,\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n } catch (err) {\n warnings.push({\n scope: 'parser:pypi',\n path,\n message: `Failed to read ${file}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'pypi', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\n/**\n * Parses Gemfile.lock GEM section:\n * GEM\n * remote: https://rubygems.org/\n * specs:\n * rails (7.1.2)\n * actionmailer (7.1.2)\n */\nfunction parseGemfileLock(raw: string): Array<{ name: string; version: string }> {\n const out: Array<{ name: string; version: string }> = [];\n const lines = raw.split('\\n');\n let inSpecs = false;\n for (const line of lines) {\n if (line.trim() === 'specs:') {\n inSpecs = true;\n continue;\n }\n if (inSpecs) {\n if (!line.startsWith(' ')) {\n inSpecs = false;\n continue;\n }\n // 4-space indented = top-level spec; 6-space indented = transitive dep\n const match = line.match(/^ {4}([A-Za-z0-9_\\-.]+) \\(([^)]+)\\)/);\n if (match?.[1] && match[2]) out.push({ name: match[1], version: match[2] });\n }\n }\n return out;\n}\n\n/**\n * Parses Gemfile — Ruby DSL:\n * gem 'rails', '~> 7.1'\n * gem \"devise\"\n * group :development do\n * gem \"rspec-rails\"\n * end\n */\nfunction parseGemfile(raw: string): Array<{ name: string; constraint?: string; dev: boolean }> {\n const out: Array<{ name: string; constraint?: string; dev: boolean }> = [];\n const lines = raw.split('\\n');\n let groupDepth = 0;\n let inDevGroup = false;\n for (const rawLine of lines) {\n const line = rawLine.split('#')[0]?.trim() ?? '';\n if (!line) continue;\n const groupMatch = line.match(/^group\\s+(:[\\w,\\s:]+?)\\s*do\\s*$/);\n if (groupMatch && groupMatch[1]) {\n groupDepth++;\n inDevGroup = /\\b(development|test)\\b/.test(groupMatch[1]);\n continue;\n }\n if (line === 'end' && groupDepth > 0) {\n groupDepth--;\n if (groupDepth === 0) inDevGroup = false;\n continue;\n }\n const gemMatch = line.match(/^gem\\s+(['\"])([A-Za-z0-9_\\-.]+)\\1(?:\\s*,\\s*(['\"])([^'\"]+)\\3)?/);\n if (gemMatch?.[2]) {\n out.push({ name: gemMatch[2], constraint: gemMatch[4], dev: inDevGroup });\n }\n }\n return out;\n}\n\nexport const parseRuby: Parser = async ({ workspace_dir, workspace_rel }): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n const lockPath = join(workspace_dir, 'Gemfile.lock');\n const gemfilePath = join(workspace_dir, 'Gemfile');\n\n // Prefer lockfile\n if (await fileExists(lockPath)) {\n try {\n const raw = await readFile(lockPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Gemfile.lock` : 'Gemfile.lock';\n // To know dep vs transitive, we also need Gemfile. Just mark all as 'dep' for now.\n const declared = new Set<string>();\n if (await fileExists(gemfilePath)) {\n try {\n const gemRaw = await readFile(gemfilePath, 'utf-8');\n for (const gem of parseGemfile(gemRaw)) declared.add(gem.name);\n } catch {\n /* non-fatal */\n }\n }\n for (const spec of parseGemfileLock(raw)) {\n // Skip if gemspec doesn't declare and we have a Gemfile — transitive\n if (declared.size > 0 && !declared.has(spec.name)) continue;\n tools.push({\n name: spec.name,\n ecosystem: 'rubygems',\n version_constraint: undefined,\n resolved_version: spec.version,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'rubygems', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:ruby',\n path: lockPath,\n message: `Failed to parse Gemfile.lock: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: Gemfile\n if (await fileExists(gemfilePath)) {\n try {\n const raw = await readFile(gemfilePath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Gemfile` : 'Gemfile';\n for (const gem of parseGemfile(raw)) {\n tools.push({\n name: gem.name,\n ecosystem: 'rubygems',\n version_constraint: gem.constraint,\n section: gem.dev ? 'dev' : 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n warnings.push({\n scope: 'parser:ruby',\n path: manifestFile,\n message: 'No Gemfile.lock — resolved_version unavailable.',\n });\n } catch (err) {\n warnings.push({\n scope: 'parser:ruby',\n path: gemfilePath,\n message: `Failed to parse Gemfile: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'rubygems', tools, warnings };\n};\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport type { ParseResult, Parser } from '../types.js';\nimport { fileExists } from '../util/fs.js';\n\ninterface PackageResolvedV1 {\n object?: {\n pins?: Array<{\n package?: string;\n state?: { version?: string; branch?: string };\n }>;\n };\n pins?: Array<{\n identity?: string;\n location?: string;\n state?: { version?: string; branch?: string };\n }>;\n}\n\n/** Extracts package identity + version from Package.resolved (v1 or v2 format). */\nfunction parsePackageResolved(raw: string): Array<{ name: string; version?: string }> {\n let doc: PackageResolvedV1;\n try {\n doc = JSON.parse(raw) as PackageResolvedV1;\n } catch {\n return [];\n }\n const out: Array<{ name: string; version?: string }> = [];\n // v2 format\n for (const pin of doc.pins ?? []) {\n if (pin.identity) out.push({ name: pin.identity, version: pin.state?.version });\n }\n // v1 format\n for (const pin of doc.object?.pins ?? []) {\n if (pin.package) out.push({ name: pin.package, version: pin.state?.version });\n }\n return out;\n}\n\n/**\n * Swift Package.swift fallback (DSL):\n * .package(url: \"https://github.com/foo/bar.git\", from: \"1.0.0\")\n * .package(url: \"...\", .upToNextMajor(from: \"2.0.0\"))\n *\n * We extract the last segment of the URL as the identity and the raw version spec.\n */\nfunction parsePackageSwift(raw: string): Array<{ name: string; constraint?: string }> {\n const out: Array<{ name: string; constraint?: string }> = [];\n const pattern = /\\.package\\(\\s*(?:name:\\s*\"[^\"]+\"\\s*,\\s*)?url:\\s*\"([^\"]+)\"\\s*,\\s*([^)]+)\\)/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(raw)) !== null) {\n const url = match[1];\n const spec = match[2]?.trim();\n if (!url) continue;\n // identity = last path segment, strip .git suffix\n const identity = url\n .split('/')\n .pop()\n ?.replace(/\\.git$/, '');\n if (!identity) continue;\n out.push({ name: identity, constraint: spec });\n }\n return out;\n}\n\nexport const parseSwift: Parser = async ({\n workspace_dir,\n workspace_rel,\n}): Promise<ParseResult> => {\n const warnings: DiscoveryWarning[] = [];\n const tools: ParseResult['tools'] = [];\n\n // Prefer Package.resolved\n const resolvedPath = join(workspace_dir, 'Package.resolved');\n if (await fileExists(resolvedPath)) {\n try {\n const raw = await readFile(resolvedPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Package.resolved` : 'Package.resolved';\n for (const pkg of parsePackageResolved(raw)) {\n tools.push({\n name: pkg.name,\n ecosystem: 'swift-pm',\n resolved_version: pkg.version,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n if (tools.length > 0) return { ecosystem: 'swift-pm', tools, warnings };\n } catch (err) {\n warnings.push({\n scope: 'parser:swift',\n path: resolvedPath,\n message: `Failed to parse Package.resolved: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Fallback: Package.swift\n const swiftPath = join(workspace_dir, 'Package.swift');\n if (await fileExists(swiftPath)) {\n try {\n const raw = await readFile(swiftPath, 'utf-8');\n const manifestFile = workspace_rel ? `${workspace_rel}/Package.swift` : 'Package.swift';\n for (const pkg of parsePackageSwift(raw)) {\n tools.push({\n name: pkg.name,\n ecosystem: 'swift-pm',\n version_constraint: pkg.constraint,\n section: 'dep',\n manifest_file: manifestFile,\n workspace_path: workspace_rel,\n });\n }\n warnings.push({\n scope: 'parser:swift',\n path: manifestFile,\n message: 'No Package.resolved — resolved_version unavailable.',\n });\n } catch (err) {\n warnings.push({\n scope: 'parser:swift',\n path: swiftPath,\n message: `Failed to parse Package.swift: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return { ecosystem: 'swift-pm', tools, warnings };\n};\n","import type { Ecosystem } from '@toolcairn/types';\nimport { resolveCargoIdentity } from './cargo.js';\nimport { resolveComposerIdentity } from './composer.js';\nimport { resolveGoIdentity } from './go.js';\nimport { resolveGradleIdentity } from './gradle.js';\nimport { resolveHexIdentity } from './hex.js';\nimport { resolveMavenIdentity } from './maven.js';\nimport { resolveNpmIdentity } from './npm.js';\nimport { resolveNugetIdentity } from './nuget.js';\nimport { resolvePubIdentity } from './pub.js';\nimport { resolvePypiIdentity } from './pypi.js';\nimport { resolveRubyIdentity } from './ruby.js';\nimport { resolveSwiftPmIdentity } from './swift-pm.js';\nimport type { ResolvedToolIdentity } from './types.js';\n\nexport type ResolverHints = { resolved_version?: string };\n\n/**\n * Per-ecosystem resolver signature. Pure local reads — no network.\n * Returns an empty identity when the installed package manifest isn't\n * locally available; the handler cascade degrades gracefully from there.\n */\nexport type Resolver = (\n workspaceAbs: string,\n projectRoot: string,\n depName: string,\n hints?: ResolverHints,\n) => Promise<ResolvedToolIdentity> | ResolvedToolIdentity;\n\nexport const RESOLVERS: Partial<Record<Ecosystem, Resolver>> = {\n npm: resolveNpmIdentity,\n pypi: resolvePypiIdentity,\n cargo: resolveCargoIdentity,\n go: (w, p, n) => resolveGoIdentity(w, p, n),\n rubygems: resolveRubyIdentity,\n maven: resolveMavenIdentity,\n gradle: resolveGradleIdentity,\n composer: resolveComposerIdentity,\n hex: resolveHexIdentity,\n pub: resolvePubIdentity,\n nuget: resolveNugetIdentity,\n 'swift-pm': resolveSwiftPmIdentity,\n};\n\nexport { normaliseGitHubUrl } from './url-normalise.js';\nexport type { ResolvedToolIdentity } from './types.js';\n","import { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { parse as parseToml } from 'smol-toml';\nimport { fileExists, isDir } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:cargo' });\n\ninterface CargoToml {\n package?: {\n name?: string;\n version?: string;\n repository?: string;\n homepage?: string;\n };\n}\n\n/**\n * Find cached source of a crate under `~/.cargo/registry/src/<index-host>-*`.\n * Each crate is checked out as `<name>-<version>`. We prefer the exact version\n * when the caller supplied it (via lockfile resolved_version); otherwise pick\n * the lexically-highest matching dir.\n */\nasync function findCachedCrate(name: string, preferredVersion?: string): Promise<string | null> {\n const registryRoot = join(homedir(), '.cargo', 'registry', 'src');\n if (!(await isDir(registryRoot))) return null;\n let indexHosts: string[];\n try {\n indexHosts = await readdir(registryRoot);\n } catch {\n return null;\n }\n const matches: string[] = [];\n for (const host of indexHosts) {\n const hostDir = join(registryRoot, host);\n if (!(await isDir(hostDir))) continue;\n let entries: string[];\n try {\n entries = await readdir(hostDir);\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (!entry.startsWith(`${name}-`)) continue;\n if (preferredVersion && entry !== `${name}-${preferredVersion}`) continue;\n const manifestPath = join(hostDir, entry, 'Cargo.toml');\n if (await fileExists(manifestPath)) matches.push(manifestPath);\n }\n }\n if (matches.length === 0) return null;\n matches.sort();\n return matches[matches.length - 1] ?? null;\n}\n\nexport async function resolveCargoIdentity(\n _workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n hints: { resolved_version?: string } = {},\n): Promise<ResolvedToolIdentity> {\n const manifestPath = await findCachedCrate(depName, hints.resolved_version);\n if (!manifestPath) return {};\n try {\n const raw = await readFile(manifestPath, 'utf-8');\n const doc = parseToml(raw) as CargoToml;\n const pkg = doc.package;\n if (!pkg) return {};\n const out: ResolvedToolIdentity = {};\n if (pkg.name && pkg.name !== depName) out.canonical_package_name = pkg.name;\n if (pkg.version) out.resolved_version = pkg.version;\n const normalised = normaliseGitHubUrl(pkg.repository ?? pkg.homepage);\n if (normalised) out.github_url = normalised;\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), manifestPath },\n 'Failed to parse cached Cargo.toml',\n );\n return {};\n }\n}\n","/**\n * Normalise any flavour of git repository URL to https://github.com/owner/repo.\n * Returns null for URLs outside github.com (we only resolve those for now —\n * other forges (gitlab, bitbucket) are a follow-up, and `undefined` stops\n * the MCP client from sending garbage to the engine's exact-match filter).\n *\n * Handles:\n * - git+https://github.com/owner/repo.git → https://github.com/owner/repo\n * - git+ssh://git@github.com/owner/repo.git → https://github.com/owner/repo\n * - git@github.com:owner/repo.git → https://github.com/owner/repo\n * - https://github.com/owner/repo/ → https://github.com/owner/repo\n * - github:owner/repo (npm shorthand) → https://github.com/owner/repo\n * - owner/repo (npm shorthand — short-form) → https://github.com/owner/repo\n */\nexport function normaliseGitHubUrl(raw: string | undefined | null): string | undefined {\n if (!raw) return undefined;\n let s = raw.trim();\n if (!s) return undefined;\n\n if (s.startsWith('git+')) s = s.slice(4);\n\n // npm shorthand: \"github:foo/bar\"\n if (s.startsWith('github:')) {\n s = `https://github.com/${s.slice(7)}`;\n }\n\n // npm short-form shorthand: \"foo/bar\" (no slashes other than the separator)\n if (/^[A-Za-z0-9_.\\-]+\\/[A-Za-z0-9_.\\-]+$/.test(s)) {\n s = `https://github.com/${s}`;\n }\n\n // git@github.com:owner/repo(.git)\n s = s.replace(/^git@github\\.com:/, 'https://github.com/');\n // ssh://git@github.com/owner/repo(.git)\n s = s.replace(/^ssh:\\/\\/git@github\\.com\\//, 'https://github.com/');\n // http → https\n s = s.replace(/^http:\\/\\//, 'https://');\n\n // Must be github.com\n if (!/^https:\\/\\/github\\.com\\//.test(s)) return undefined;\n\n // Strip trailing / and .git\n s = s.replace(/\\.git$/, '');\n s = s.replace(/\\/$/, '');\n\n // Guard: must have exactly owner/repo path\n const match = s.match(/^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)/);\n if (!match) return undefined;\n return `https://github.com/${match[1]}/${match[2]}`;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { fileExists } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:composer' });\n\ninterface InstalledComposerJson {\n name?: string;\n version?: string;\n homepage?: string;\n source?: { url?: string };\n support?: { source?: string };\n}\n\n/**\n * Read the installed vendored composer.json for `<vendor>/<pkg>` and extract\n * canonical name + github_url. Composer lays installed deps out as\n * `<ws>/vendor/<vendor>/<pkg>/composer.json`, so the dep name is already a\n * path hint.\n */\nexport async function resolveComposerIdentity(\n workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n): Promise<ResolvedToolIdentity> {\n // depName is \"vendor/package\" — matches the vendor dir layout directly.\n const path = join(workspaceAbs, 'vendor', depName, 'composer.json');\n if (!(await fileExists(path))) return {};\n try {\n const pkg = JSON.parse(await readFile(path, 'utf-8')) as InstalledComposerJson;\n const out: ResolvedToolIdentity = {};\n if (pkg.name && pkg.name !== depName) out.canonical_package_name = pkg.name;\n if (pkg.version) out.resolved_version = pkg.version;\n const candidateUrl = pkg.source?.url ?? pkg.support?.source ?? pkg.homepage;\n const normalised = normaliseGitHubUrl(candidateUrl);\n if (normalised) out.github_url = normalised;\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to parse installed composer.json',\n );\n return {};\n }\n}\n","import type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\n/**\n * Go modules ARE the import path — no filesystem lookup required. For any\n * github.com-hosted module, the github_url is derivable in pure constant time:\n * github.com/vercel/next.js → https://github.com/vercel/next.js\n * github.com/foo/bar/v2 → https://github.com/foo/bar (strip /vN)\n * github.com/foo/bar/subpackage → https://github.com/foo/bar (owner/repo only)\n *\n * Non-github modules (e.g. golang.org/x/net, gopkg.in/*, bitbucket.org/*)\n * return an empty identity — the MCP resolver cascade catches them via\n * registry_package_keys if indexed, or Memgraph name fallback.\n */\nexport function resolveGoIdentity(\n _workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n): ResolvedToolIdentity {\n if (!depName.startsWith('github.com/')) return {};\n const tail = depName.slice('github.com/'.length);\n const parts = tail.split('/');\n if (parts.length < 2 || !parts[0] || !parts[1]) return {};\n const owner = parts[0];\n let repo = parts[1];\n // Strip /vN version-suffix segments and sub-packages by only keeping owner/repo.\n repo = repo.replace(/\\.git$/, '');\n const url = normaliseGitHubUrl(`https://github.com/${owner}/${repo}`);\n return url ? { github_url: url } : {};\n}\n","import { readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { isDir } from '../util/fs.js';\nimport { parsePomIdentity } from './pom-shared.js';\nimport type { ResolvedToolIdentity } from './types.js';\n\n/**\n * Find a cached .pom under Gradle's modules cache:\n * ~/.gradle/caches/modules-2/files-2.1/<group>/<artifact>/<ver>/<hash>/<artifact>-<ver>.pom\n */\nasync function findGradlePom(\n groupId: string,\n artifactId: string,\n preferredVersion?: string,\n): Promise<string | null> {\n const base = join(homedir(), '.gradle', 'caches', 'modules-2', 'files-2.1', groupId, artifactId);\n if (!(await isDir(base))) return null;\n let versions: string[];\n try {\n versions = await readdir(base);\n } catch {\n return null;\n }\n const chosen =\n preferredVersion && versions.includes(preferredVersion)\n ? preferredVersion\n : versions.sort().at(-1);\n if (!chosen) return null;\n\n const versionDir = join(base, chosen);\n let hashDirs: string[];\n try {\n hashDirs = await readdir(versionDir);\n } catch {\n return null;\n }\n for (const hash of hashDirs) {\n const candidate = join(versionDir, hash, `${artifactId}-${chosen}.pom`);\n // We can't stat here without an import; just return — parsePomIdentity\n // gracefully no-ops when the file is missing, so the first candidate wins.\n return candidate;\n }\n return null;\n}\n\nexport async function resolveGradleIdentity(\n _workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n hints: { resolved_version?: string } = {},\n): Promise<ResolvedToolIdentity> {\n const colon = depName.indexOf(':');\n if (colon < 0) return {};\n const groupId = depName.slice(0, colon);\n const artifactId = depName.slice(colon + 1);\n if (!groupId || !artifactId) return {};\n const pomPath = await findGradlePom(groupId, artifactId, hints.resolved_version);\n if (!pomPath) return {};\n return parsePomIdentity(pomPath, depName);\n}\n","import { readFile } from 'node:fs/promises';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { XMLParser } from 'fast-xml-parser';\nimport { fileExists } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:pom' });\n\ninterface Pom {\n project?: {\n groupId?: string;\n artifactId?: string;\n version?: string;\n url?: string;\n scm?: { url?: string; connection?: string; developerConnection?: string };\n };\n}\n\n/**\n * Parse a cached .pom file (Maven or Gradle — same schema) and derive\n * canonical_package_name + github_url.\n *\n * Canonical form for Java/Kotlin artifacts is `groupId:artifactId`, which is\n * what the upstream parsers emit as the `name`. If that matches what the\n * caller already had, canonical_package_name is omitted.\n */\nexport async function parsePomIdentity(\n path: string,\n depName: string,\n): Promise<ResolvedToolIdentity> {\n if (!(await fileExists(path))) return {};\n try {\n const raw = await readFile(path, 'utf-8');\n const parser = new XMLParser({ ignoreAttributes: true, parseTagValue: true });\n const doc = parser.parse(raw) as Pom;\n const project = doc.project;\n if (!project) return {};\n const out: ResolvedToolIdentity = {};\n const canonical =\n project.groupId && project.artifactId\n ? `${project.groupId}:${project.artifactId}`\n : undefined;\n if (canonical && canonical !== depName) out.canonical_package_name = canonical;\n if (project.version) out.resolved_version = project.version;\n const candidateUrls = [\n project.scm?.url,\n project.scm?.connection,\n project.scm?.developerConnection,\n project.url,\n ];\n for (const u of candidateUrls) {\n const normalised = normaliseGitHubUrl(u);\n if (normalised) {\n out.github_url = normalised;\n break;\n }\n }\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to parse .pom',\n );\n return {};\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { fileExists } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:hex' });\n\n/**\n * Elixir Mix places installed deps under `<project>/deps/<name>/`.\n * hex_metadata.config is the canonical metadata (Erlang term format). The\n * `links` field typically contains `{<<\"GitHub\">>, <<\"url\">>}`. We regex\n * the URL out — parsing full Erlang terms is overkill.\n *\n * Fallback: mix.exs sometimes sets @source_url or source_url: in the project()\n * map.\n */\nfunction extractHexMetadataUrl(raw: string): string | undefined {\n // <<\"GitHub\">>, <<\"https://...\">> — link in the `links` proplist\n let match = raw.match(/<<\"GitHub\">>\\s*,\\s*<<\"([^\"]+)\">>/i);\n if (match?.[1]) return match[1];\n // Generic <<\"<label>\">>, <<\"<url>\">> where the label contains \"github\"\n match = raw.match(/<<\"[^\"]*github[^\"]*\">>\\s*,\\s*<<\"(https?:\\/\\/[^\"]+)\">>/i);\n if (match?.[1]) return match[1];\n return undefined;\n}\n\nfunction extractMixExsUrl(raw: string): string | undefined {\n // @source_url \"https://...\" or @source_url(\"https://...\")\n const atMatch = raw.match(/@source_url\\s*\\(?\\s*[\"']([^\"']+)[\"']/);\n if (atMatch?.[1]) return atMatch[1];\n // source_url: \"https://...\"\n const kwMatch = raw.match(/\\bsource_url\\s*:\\s*[\"']([^\"']+)[\"']/);\n if (kwMatch?.[1]) return kwMatch[1];\n return undefined;\n}\n\nexport async function resolveHexIdentity(\n workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n): Promise<ResolvedToolIdentity> {\n const depDir = join(workspaceAbs, 'deps', depName);\n const out: ResolvedToolIdentity = {};\n\n const metaPath = join(depDir, 'hex_metadata.config');\n if (await fileExists(metaPath)) {\n try {\n const raw = await readFile(metaPath, 'utf-8');\n const url = extractHexMetadataUrl(raw);\n const normalised = normaliseGitHubUrl(url);\n if (normalised) out.github_url = normalised;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), metaPath },\n 'Failed to read hex_metadata.config',\n );\n }\n }\n\n // Fallback to mix.exs inside the dep if we didn't find a URL yet\n if (!out.github_url) {\n const mixPath = join(depDir, 'mix.exs');\n if (await fileExists(mixPath)) {\n try {\n const raw = await readFile(mixPath, 'utf-8');\n const url = extractMixExsUrl(raw);\n const normalised = normaliseGitHubUrl(url);\n if (normalised) out.github_url = normalised;\n } catch {\n /* silent */\n }\n }\n }\n\n return out;\n}\n","import { readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { isDir } from '../util/fs.js';\nimport { parsePomIdentity } from './pom-shared.js';\nimport type { ResolvedToolIdentity } from './types.js';\n\n/**\n * Look up the installed .pom for \"<group>:<artifact>\" under `~/.m2/repository`.\n * Maven stores each version under `<group-with-slashes>/<artifact>/<ver>/`.\n * Picks the lexically-highest version present when `resolved_version` is\n * unknown.\n */\nasync function findMavenPom(\n groupId: string,\n artifactId: string,\n preferredVersion?: string,\n): Promise<string | null> {\n const groupPath = groupId.replace(/\\./g, '/');\n const base = join(homedir(), '.m2', 'repository', groupPath, artifactId);\n if (!(await isDir(base))) return null;\n let versions: string[];\n try {\n versions = await readdir(base);\n } catch {\n return null;\n }\n let chosen: string | undefined;\n if (preferredVersion && versions.includes(preferredVersion)) {\n chosen = preferredVersion;\n } else {\n versions.sort();\n chosen = versions[versions.length - 1];\n }\n if (!chosen) return null;\n return join(base, chosen, `${artifactId}-${chosen}.pom`);\n}\n\nexport async function resolveMavenIdentity(\n _workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n hints: { resolved_version?: string } = {},\n): Promise<ResolvedToolIdentity> {\n const colon = depName.indexOf(':');\n if (colon < 0) return {};\n const groupId = depName.slice(0, colon);\n const artifactId = depName.slice(colon + 1);\n if (!groupId || !artifactId) return {};\n const pomPath = await findMavenPom(groupId, artifactId, hints.resolved_version);\n if (!pomPath) return {};\n return parsePomIdentity(pomPath, depName);\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { fileExists } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:npm' });\n\n/**\n * npm `repository` field shapes (all are valid per package.json spec):\n * \"repository\": \"github:owner/repo\"\n * \"repository\": \"owner/repo\"\n * \"repository\": \"https://github.com/owner/repo.git\"\n * \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/owner/repo.git\" }\n * \"repository\": { \"type\": \"git\", \"url\": \"...\", \"directory\": \"packages/foo\" }\n */\ninterface InstalledPackageJson {\n name?: string;\n version?: string;\n repository?: string | { type?: string; url?: string; directory?: string };\n homepage?: string;\n}\n\nfunction extractRepoUrl(pkg: InstalledPackageJson): string | undefined {\n const r = pkg.repository;\n if (!r) return undefined;\n if (typeof r === 'string') return r;\n return r.url;\n}\n\n/**\n * Walk up from workspaceAbs looking for node_modules/<depName>/package.json.\n * npm workspaces / pnpm hoist installed deps somewhere between the workspace\n * and the repo root, so we climb until we either find it or hit the filesystem\n * root. Returns `null` when no installed manifest is present.\n */\nasync function findInstalledManifest(\n workspaceAbs: string,\n projectRoot: string,\n depKey: string,\n): Promise<string | null> {\n let cursor = workspaceAbs;\n // Stop at projectRoot's parent so we don't stray outside the repo.\n const stopAt = projectRoot;\n // Safety cap on traversal depth in case the path normalisation misfires.\n for (let i = 0; i < 10; i++) {\n const candidate = join(cursor, 'node_modules', depKey, 'package.json');\n if (await fileExists(candidate)) return candidate;\n if (cursor === stopAt) break;\n const parent = join(cursor, '..');\n if (parent === cursor) break;\n cursor = parent;\n }\n return null;\n}\n\n/**\n * Resolve canonical package name + github_url for a detected npm dep by reading\n * its INSTALLED manifest under node_modules. Pure local (no network, no registry\n * hit). Silently returns an empty identity when node_modules isn't present —\n * the MCP handler then falls back to raw dep-key matching server-side.\n */\nexport async function resolveNpmIdentity(\n workspaceAbs: string,\n projectRoot: string,\n depKey: string,\n): Promise<ResolvedToolIdentity> {\n const manifestPath = await findInstalledManifest(workspaceAbs, projectRoot, depKey);\n if (!manifestPath) return {};\n let pkg: InstalledPackageJson;\n try {\n pkg = JSON.parse(await readFile(manifestPath, 'utf-8')) as InstalledPackageJson;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), manifestPath },\n 'Failed to parse installed package.json — skipping url resolution',\n );\n return {};\n }\n const out: ResolvedToolIdentity = {};\n if (pkg.name && pkg.name !== depKey) {\n // Only set canonical_package_name when it actually differs from the dep key\n // (common case: aliased installs). Otherwise we'd send redundant data.\n out.canonical_package_name = pkg.name;\n }\n if (pkg.version) {\n out.resolved_version = pkg.version;\n }\n const url = extractRepoUrl(pkg);\n const normalised = normaliseGitHubUrl(url);\n if (normalised) out.github_url = normalised;\n return out;\n}\n","import { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { XMLParser } from 'fast-xml-parser';\nimport { fileExists, isDir } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:nuget' });\n\ninterface Nuspec {\n package?: {\n metadata?: {\n id?: string;\n version?: string;\n projectUrl?: string;\n repository?: { '@_url'?: string } | { url?: string };\n };\n };\n}\n\n/**\n * Find the installed .nuspec under the global NuGet cache:\n * ~/.nuget/packages/<name-lowercase>/<ver>/<name-lowercase>.nuspec\n */\nasync function findNuspec(depName: string, preferredVersion?: string): Promise<string | null> {\n const pkgRoot = join(homedir(), '.nuget', 'packages', depName.toLowerCase());\n if (!(await isDir(pkgRoot))) return null;\n let versions: string[];\n try {\n versions = await readdir(pkgRoot);\n } catch {\n return null;\n }\n const chosen =\n preferredVersion && versions.includes(preferredVersion)\n ? preferredVersion\n : versions.sort().at(-1);\n if (!chosen) return null;\n const path = join(pkgRoot, chosen, `${depName.toLowerCase()}.nuspec`);\n return (await fileExists(path)) ? path : null;\n}\n\nexport async function resolveNugetIdentity(\n _workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n hints: { resolved_version?: string } = {},\n): Promise<ResolvedToolIdentity> {\n const path = await findNuspec(depName, hints.resolved_version);\n if (!path) return {};\n try {\n const raw = await readFile(path, 'utf-8');\n const parser = new XMLParser({ ignoreAttributes: false });\n const doc = parser.parse(raw) as Nuspec;\n const meta = doc.package?.metadata;\n if (!meta) return {};\n const out: ResolvedToolIdentity = {};\n if (meta.id && meta.id !== depName) out.canonical_package_name = meta.id;\n if (meta.version) out.resolved_version = meta.version;\n const repoUrl =\n (meta.repository as { '@_url'?: string } | undefined)?.['@_url'] ??\n (meta.repository as { url?: string } | undefined)?.url;\n const candidate = normaliseGitHubUrl(repoUrl ?? meta.projectUrl);\n if (candidate) out.github_url = candidate;\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to parse .nuspec',\n );\n return {};\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { parse as parseYaml } from 'yaml';\nimport { fileExists } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:pub' });\n\ninterface PubSpec {\n name?: string;\n version?: string;\n homepage?: string;\n repository?: string;\n issue_tracker?: string;\n}\n\n/**\n * Dart/Flutter pub cache locations:\n * macOS/Linux: ~/.pub-cache/hosted/pub.dev/<name>-<ver>/pubspec.yaml\n * Windows : %LOCALAPPDATA%\\Pub\\Cache\\hosted\\pub.dev\\<name>-<ver>\\pubspec.yaml\n */\nfunction pubCacheRoot(): string {\n if (platform() === 'win32') {\n const local = process.env.LOCALAPPDATA;\n if (local) return join(local, 'Pub', 'Cache', 'hosted', 'pub.dev');\n }\n return join(homedir(), '.pub-cache', 'hosted', 'pub.dev');\n}\n\nasync function findPubspec(depName: string, version?: string): Promise<string | null> {\n const root = pubCacheRoot();\n if (version) {\n const direct = join(root, `${depName}-${version}`, 'pubspec.yaml');\n return (await fileExists(direct)) ? direct : null;\n }\n // Fallback: pick any installed version of this package.\n try {\n const { readdir } = await import('node:fs/promises');\n const entries = await readdir(root);\n const matches = entries.filter((e) => e.startsWith(`${depName}-`)).sort();\n const chosen = matches.at(-1);\n if (!chosen) return null;\n const candidate = join(root, chosen, 'pubspec.yaml');\n return (await fileExists(candidate)) ? candidate : null;\n } catch {\n return null;\n }\n}\n\nexport async function resolvePubIdentity(\n _workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n hints: { resolved_version?: string } = {},\n): Promise<ResolvedToolIdentity> {\n const path = await findPubspec(depName, hints.resolved_version);\n if (!path) return {};\n try {\n const raw = await readFile(path, 'utf-8');\n const pkg = parseYaml(raw) as PubSpec;\n const out: ResolvedToolIdentity = {};\n if (pkg.name && pkg.name !== depName) out.canonical_package_name = pkg.name;\n if (pkg.version) out.resolved_version = pkg.version;\n const candidate = normaliseGitHubUrl(pkg.repository ?? pkg.homepage);\n if (candidate) out.github_url = candidate;\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to parse pubspec.yaml',\n );\n return {};\n }\n}\n","import { readFile, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { fileExists, isDir } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:pypi' });\n\n/**\n * Likely site-packages locations inside a project virtualenv.\n * Windows: \".venv/Lib/site-packages/\"\n * POSIX : \".venv/lib/python<X>/site-packages/\" (python<X> globbed at runtime).\n */\nasync function findSitePackagesDirs(workspaceAbs: string): Promise<string[]> {\n const candidates: string[] = [];\n const venvs = ['.venv', 'venv', '.virtualenv'];\n\n for (const venv of venvs) {\n const venvDir = join(workspaceAbs, venv);\n if (!(await isDir(venvDir))) continue;\n\n // Windows layout\n const winSite = join(venvDir, 'Lib', 'site-packages');\n if (await isDir(winSite)) candidates.push(winSite);\n\n // POSIX layout - glob the versioned python<X> dir under lib/\n const libDir = join(venvDir, 'lib');\n if (await isDir(libDir)) {\n try {\n for (const entry of await readdir(libDir)) {\n if (!entry.startsWith('python')) continue;\n const sp = join(libDir, entry, 'site-packages');\n if (await isDir(sp)) candidates.push(sp);\n }\n } catch {\n /* skip */\n }\n }\n }\n return candidates;\n}\n\n/** Normalise PEP 503 — lowercase, '_' and '.' collapsed to '-'. */\nfunction normalisePypiName(name: string): string {\n return name.toLowerCase().replace(/[._]+/g, '-');\n}\n\n/**\n * METADATA files live under `<name>-<version>.dist-info/`. Project names in\n * the dir prefix follow PEP 503 normalisation; loose match both.\n */\nasync function findMetadataPath(siteDir: string, depName: string): Promise<string | null> {\n const normalised = normalisePypiName(depName);\n let entries: string[];\n try {\n entries = await readdir(siteDir);\n } catch {\n return null;\n }\n for (const entry of entries) {\n if (!entry.endsWith('.dist-info')) continue;\n // Strip '-<version>.dist-info' to compare names\n const base = entry.replace(/-[^-]+\\.dist-info$/, '');\n if (normalisePypiName(base) === normalised) {\n const metadataPath = join(siteDir, entry, 'METADATA');\n if (await fileExists(metadataPath)) return metadataPath;\n }\n }\n return null;\n}\n\n/**\n * Parse an RFC 822-style METADATA file into a Map. Only reads the header\n * block up to the first blank line (the long description after that is\n * large and useless for our needs).\n */\nfunction parseMetadata(raw: string): { name?: string; version?: string; urls: string[] } {\n const urls: string[] = [];\n let name: string | undefined;\n let version: string | undefined;\n const lines = raw.split('\\n');\n for (const line of lines) {\n if (line.trim() === '') break;\n const colon = line.indexOf(':');\n if (colon < 0) continue;\n const key = line.slice(0, colon).trim();\n const val = line.slice(colon + 1).trim();\n if (key === 'Name' && !name) name = val;\n else if (key === 'Version' && !version) version = val;\n else if (key === 'Home-page') urls.push(val);\n else if (key === 'Project-URL') {\n // Format: \"Label, https://...\"\n const comma = val.indexOf(',');\n if (comma >= 0) urls.push(val.slice(comma + 1).trim());\n else urls.push(val);\n }\n }\n return { name, version, urls };\n}\n\n/**\n * Resolve canonical name + github_url for a pypi dep by reading its installed\n * .dist-info/METADATA. Prefers project-repo URLs over homepages. Silent no-op\n * when no venv / METADATA is present.\n */\nexport async function resolvePypiIdentity(\n workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n): Promise<ResolvedToolIdentity> {\n const siteDirs = await findSitePackagesDirs(workspaceAbs);\n for (const siteDir of siteDirs) {\n const path = await findMetadataPath(siteDir, depName);\n if (!path) continue;\n try {\n const raw = await readFile(path, 'utf-8');\n const { name, version, urls } = parseMetadata(raw);\n const out: ResolvedToolIdentity = {};\n if (name && normalisePypiName(name) !== normalisePypiName(depName)) {\n out.canonical_package_name = name;\n }\n if (version) out.resolved_version = version;\n // Walk urls looking for a github.com match — prioritise explicit repo URLs.\n for (const u of urls) {\n const normalised = normaliseGitHubUrl(u);\n if (normalised) {\n out.github_url = normalised;\n break;\n }\n }\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to parse METADATA',\n );\n }\n }\n return {};\n}\n","import { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { fileExists, isDir } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:ruby' });\n\n/**\n * Find a candidate \"<name>-<ver>.gemspec\" in well-known locations:\n * - <ws>/vendor/bundle/ruby/<X>/specifications/\n * - ~/.gem/specifications/\n * - ~/.rbenv/versions/<X>/lib/ruby/gems/<Y>/specifications/ (opportunistic)\n * - System ruby (rare, skipped)\n * (The <X>/<Y> placeholders are enumerated via readdir at runtime.)\n */\nasync function findGemspec(\n workspaceAbs: string,\n depName: string,\n preferredVersion?: string,\n): Promise<string | null> {\n const specsDirs: string[] = [];\n const bundleRubyDir = join(workspaceAbs, 'vendor', 'bundle', 'ruby');\n if (await isDir(bundleRubyDir)) {\n try {\n for (const entry of await readdir(bundleRubyDir)) {\n const dir = join(bundleRubyDir, entry, 'specifications');\n if (await isDir(dir)) specsDirs.push(dir);\n }\n } catch {\n /* skip */\n }\n }\n const homeSpecs = join(homedir(), '.gem', 'specifications');\n if (await isDir(homeSpecs)) specsDirs.push(homeSpecs);\n\n for (const dir of specsDirs) {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n continue;\n }\n const matches = entries\n .filter((e) => e.endsWith('.gemspec') && e.startsWith(`${depName}-`))\n .filter((e) => {\n if (!preferredVersion) return true;\n return e === `${depName}-${preferredVersion}.gemspec`;\n })\n .sort();\n const chosen = matches.at(-1);\n if (chosen) {\n const path = join(dir, chosen);\n if (await fileExists(path)) return path;\n }\n }\n return null;\n}\n\n/**\n * Gemspecs are Ruby DSL, but the relevant fields follow stable patterns.\n * We extract via regex — safer than executing Ruby code.\n */\nfunction extractGemspecFields(raw: string): {\n name?: string;\n version?: string;\n homepage?: string;\n source_code_uri?: string;\n} {\n const out: {\n name?: string;\n version?: string;\n homepage?: string;\n source_code_uri?: string;\n } = {};\n const pick = (pattern: RegExp): string | undefined => {\n const m = raw.match(pattern);\n return m ? m[1] : undefined;\n };\n out.name = pick(/(?:s|spec)\\.name\\s*=\\s*(['\"])([^'\"]+)\\1/)\n ? raw.match(/(?:s|spec)\\.name\\s*=\\s*['\"]([^'\"]+)['\"]/)?.[1]\n : undefined;\n out.version = raw.match(/(?:s|spec)\\.version\\s*=\\s*['\"]([^'\"]+)['\"]/)?.[1];\n out.homepage = raw.match(/(?:s|spec)\\.homepage\\s*=\\s*['\"]([^'\"]+)['\"]/)?.[1];\n out.source_code_uri = raw.match(/[\"']source_code_uri[\"']\\s*=>\\s*[\"']([^'\"]+)[\"']/)?.[1];\n return out;\n}\n\nexport async function resolveRubyIdentity(\n workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n hints: { resolved_version?: string } = {},\n): Promise<ResolvedToolIdentity> {\n const path = await findGemspec(workspaceAbs, depName, hints.resolved_version);\n if (!path) return {};\n try {\n const raw = await readFile(path, 'utf-8');\n const fields = extractGemspecFields(raw);\n const out: ResolvedToolIdentity = {};\n if (fields.name && fields.name !== depName) out.canonical_package_name = fields.name;\n if (fields.version) out.resolved_version = fields.version;\n const candidate = normaliseGitHubUrl(fields.source_code_uri ?? fields.homepage);\n if (candidate) out.github_url = candidate;\n return out;\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to read/parse gemspec',\n );\n return {};\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { fileExists } from '../util/fs.js';\nimport type { ResolvedToolIdentity } from './types.js';\nimport { normaliseGitHubUrl } from './url-normalise.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:resolver:swift-pm' });\n\ninterface PackageResolvedV1 {\n object?: {\n pins?: Array<{ package?: string; repositoryURL?: string; state?: { version?: string } }>;\n };\n pins?: Array<{ identity?: string; location?: string; state?: { version?: string } }>;\n}\n\n/**\n * SwiftPM records canonical VCS URLs in Package.resolved — one line per pin.\n * The upstream parser already reads this file; the resolver reads it again\n * (cheap, no I/O budget to care about) to get an authoritative github_url\n * per dep without a filesystem walk through ~/Library/Caches.\n */\nexport async function resolveSwiftPmIdentity(\n workspaceAbs: string,\n _projectRoot: string,\n depName: string,\n): Promise<ResolvedToolIdentity> {\n const path = join(workspaceAbs, 'Package.resolved');\n if (!(await fileExists(path))) return {};\n try {\n const raw = await readFile(path, 'utf-8');\n const doc = JSON.parse(raw) as PackageResolvedV1;\n const out: ResolvedToolIdentity = {};\n // v2 format: { pins: [{ identity, location, state: {version} }] }\n for (const pin of doc.pins ?? []) {\n if (pin.identity === depName) {\n if (pin.state?.version) out.resolved_version = pin.state.version;\n const normalised = normaliseGitHubUrl(pin.location);\n if (normalised) out.github_url = normalised;\n return out;\n }\n }\n // v1 format: { object: { pins: [{ package, repositoryURL, state }] } }\n for (const pin of doc.object?.pins ?? []) {\n if (pin.package === depName) {\n if (pin.state?.version) out.resolved_version = pin.state.version;\n const normalised = normaliseGitHubUrl(pin.repositoryURL);\n if (normalised) out.github_url = normalised;\n return out;\n }\n }\n return {};\n } catch (err) {\n logger.debug(\n { err: err instanceof Error ? err.message : String(err), path },\n 'Failed to parse Package.resolved during resolve',\n );\n return {};\n }\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport { IGNORED_DIRS, isDir } from '../util/fs.js';\n\n/**\n * Minimal glob-pattern expansion for workspace declarations.\n * Handles:\n * - exact paths: \"apps/web\"\n * - single-level wildcards: \"packages/*\"\n * - recursive wildcards: \"packages/**\" (treated same as packages/* + one level deep)\n * - negation: \"!packages/internal-*\" (excluded post-match)\n *\n * This is intentionally small — we don't need full minimatch semantics because\n * workspace globs are universally \"<prefix>/*\" or \"<prefix>/**\" in practice.\n */\nexport async function expandWorkspaceGlobs(rootDir: string, patterns: string[]): Promise<string[]> {\n const excluded = new Set<string>();\n const included = new Set<string>();\n\n for (const raw of patterns) {\n const pattern = raw.trim();\n if (!pattern) continue;\n const negated = pattern.startsWith('!');\n const clean = negated ? pattern.slice(1) : pattern;\n // Normalise separators to POSIX for pattern matching; join() later restores OS.\n const normalised = clean.replace(/\\\\/g, '/');\n const matches = await matchPattern(rootDir, normalised);\n const target = negated ? excluded : included;\n for (const m of matches) target.add(m);\n }\n\n return [...included].filter((p) => !excluded.has(p)).sort();\n}\n\nasync function matchPattern(rootDir: string, pattern: string): Promise<string[]> {\n const parts = pattern.split('/').filter(Boolean);\n const results: string[] = [];\n await walkPattern(rootDir, rootDir, parts, 0, results);\n return results;\n}\n\nasync function walkPattern(\n rootDir: string,\n currentDir: string,\n parts: string[],\n index: number,\n out: string[],\n): Promise<void> {\n if (index >= parts.length) {\n if (await isDir(currentDir)) out.push(currentDir);\n return;\n }\n const segment = parts[index];\n if (!segment) return;\n\n if (segment === '**') {\n // Match this level AND one level deep (common workspace pattern)\n await walkPattern(rootDir, currentDir, parts, index + 1, out);\n try {\n const entries = await readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) continue;\n await walkPattern(rootDir, join(currentDir, entry.name), parts, index, out);\n }\n } catch {\n /* skip */\n }\n return;\n }\n\n if (segment.includes('*')) {\n const re = globSegmentToRegex(segment);\n try {\n const entries = await readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) continue;\n if (re.test(entry.name)) {\n await walkPattern(rootDir, join(currentDir, entry.name), parts, index + 1, out);\n }\n }\n } catch {\n /* skip */\n }\n return;\n }\n\n // Literal segment\n await walkPattern(rootDir, join(currentDir, segment), parts, index + 1, out);\n}\n\nfunction globSegmentToRegex(segment: string): RegExp {\n const escaped = segment.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\n/** Convert absolute workspace dir to project-root-relative path with forward slashes. */\nexport function toRelPosix(projectRoot: string, absPath: string): string {\n const rel = relative(projectRoot, absPath);\n return rel.split(sep).join('/');\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DiscoveryWarning } from '@toolcairn/types';\nimport { parse as parseToml } from 'smol-toml';\nimport { parse as parseYaml } from 'yaml';\nimport { fileExists } from '../util/fs.js';\nimport { expandWorkspaceGlobs, toRelPosix } from './glob.js';\n\n/** Workspace declaration kinds we look for (in priority order per-dir). */\nconst WORKSPACE_FILES = [\n 'pnpm-workspace.yaml',\n 'package.json', // yarn / npm workspaces\n 'Cargo.toml', // [workspace] members\n 'go.work', // Go workspaces\n 'turbo.json', // often implies pnpm workspaces — don't add globs itself\n 'nx.json',\n 'lerna.json',\n] as const;\n\ninterface PackageJson {\n workspaces?: string[] | { packages?: string[] };\n}\n\ninterface PnpmWorkspace {\n packages?: string[];\n}\n\ninterface CargoWorkspaceToml {\n workspace?: { members?: string[] };\n}\n\ninterface LernaJson {\n packages?: string[];\n}\n\ninterface NxJson {\n workspaceLayout?: { projectsDir?: string };\n}\n\n/**\n * Discover all workspace roots inside a project.\n * Always includes the root itself. Then walks recursive workspace declarations up to `maxDepth`.\n * Returns absolute paths of every directory that should be scanned for manifests.\n */\nexport async function discoverWorkspaces(\n projectRoot: string,\n maxDepth = 5,\n): Promise<{ paths: string[]; warnings: DiscoveryWarning[] }> {\n const warnings: DiscoveryWarning[] = [];\n const discovered = new Set<string>([projectRoot]);\n const visited = new Set<string>();\n\n const queue: Array<{ dir: string; depth: number }> = [{ dir: projectRoot, depth: 0 }];\n\n while (queue.length > 0) {\n const { dir, depth } = queue.shift()!;\n if (visited.has(dir) || depth > maxDepth) continue;\n visited.add(dir);\n\n const globs = await readWorkspaceGlobs(dir, warnings);\n if (globs.length === 0) continue;\n\n const expanded = await expandWorkspaceGlobs(dir, globs);\n for (const sub of expanded) {\n if (!discovered.has(sub)) {\n discovered.add(sub);\n queue.push({ dir: sub, depth: depth + 1 });\n }\n }\n }\n\n return { paths: [...discovered].sort(), warnings };\n}\n\nasync function readWorkspaceGlobs(dir: string, warnings: DiscoveryWarning[]): Promise<string[]> {\n const globs: string[] = [];\n\n // pnpm-workspace.yaml\n const pnpmPath = join(dir, 'pnpm-workspace.yaml');\n if (await fileExists(pnpmPath)) {\n try {\n const doc = parseYaml(await readFile(pnpmPath, 'utf-8')) as PnpmWorkspace;\n if (Array.isArray(doc.packages)) globs.push(...doc.packages);\n } catch (err) {\n warnings.push({\n scope: 'workspace:pnpm',\n path: pnpmPath,\n message: `Failed to parse pnpm-workspace.yaml: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // package.json workspaces (npm / yarn)\n const pkgPath = join(dir, 'package.json');\n if (await fileExists(pkgPath)) {\n try {\n const doc = JSON.parse(await readFile(pkgPath, 'utf-8')) as PackageJson;\n if (Array.isArray(doc.workspaces)) {\n globs.push(...doc.workspaces);\n } else if (doc.workspaces && Array.isArray(doc.workspaces.packages)) {\n globs.push(...doc.workspaces.packages);\n }\n } catch (err) {\n warnings.push({\n scope: 'workspace:package-json',\n path: pkgPath,\n message: `Failed to parse package.json#workspaces: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // Cargo.toml [workspace] members\n const cargoPath = join(dir, 'Cargo.toml');\n if (await fileExists(cargoPath)) {\n try {\n const doc = parseToml(await readFile(cargoPath, 'utf-8')) as CargoWorkspaceToml;\n if (Array.isArray(doc.workspace?.members)) globs.push(...doc.workspace.members);\n } catch (err) {\n warnings.push({\n scope: 'workspace:cargo',\n path: cargoPath,\n message: `Failed to parse Cargo workspace: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // go.work\n const goWorkPath = join(dir, 'go.work');\n if (await fileExists(goWorkPath)) {\n try {\n const raw = await readFile(goWorkPath, 'utf-8');\n const useMatch = raw.match(/use\\s*\\(([^)]*)\\)/s);\n if (useMatch?.[1]) {\n for (const line of useMatch[1].split('\\n')) {\n const trimmed = line.trim().replace(/^['\"]|['\"]$/g, '');\n if (trimmed && !trimmed.startsWith('//')) globs.push(trimmed);\n }\n } else {\n for (const line of raw.split('\\n')) {\n const m = line.match(/^\\s*use\\s+(.+)$/);\n if (m?.[1]) globs.push(m[1].trim().replace(/^['\"]|['\"]$/g, ''));\n }\n }\n } catch (err) {\n warnings.push({\n scope: 'workspace:go',\n path: goWorkPath,\n message: `Failed to parse go.work: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // lerna.json\n const lernaPath = join(dir, 'lerna.json');\n if (await fileExists(lernaPath)) {\n try {\n const doc = JSON.parse(await readFile(lernaPath, 'utf-8')) as LernaJson;\n if (Array.isArray(doc.packages)) globs.push(...doc.packages);\n } catch (err) {\n warnings.push({\n scope: 'workspace:lerna',\n path: lernaPath,\n message: `Failed to parse lerna.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // nx.json — defaults to \"packages/*\" when projectsDir unset\n const nxPath = join(dir, 'nx.json');\n if (await fileExists(nxPath)) {\n try {\n const doc = JSON.parse(await readFile(nxPath, 'utf-8')) as NxJson;\n const base = doc.workspaceLayout?.projectsDir ?? 'packages';\n globs.push(`${base}/*`);\n } catch (err) {\n warnings.push({\n scope: 'workspace:nx',\n path: nxPath,\n message: `Failed to parse nx.json: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n return globs;\n}\n\n/**\n * Given a set of absolute workspace paths, produce `{path, manifest, ecosystem}`\n * entries for each workspace that has at least one manifest. Consumed by scanProject\n * to populate `project.subprojects`.\n */\nexport function summariseSubprojects(\n projectRoot: string,\n workspaces: string[],\n): Array<{ workspace_path: string; rel: string }> {\n return workspaces.map((abs) => ({ workspace_path: abs, rel: toRelPosix(projectRoot, abs) }));\n}\n","// Agent instruction templates for toolcairn_init.\n// Each function returns the section content to inject into the agent's instruction file.\n// The agent writes the content to the appropriate file — MCP server never touches the filesystem.\n\nexport type AgentType =\n | 'claude'\n | 'cursor'\n | 'windsurf'\n | 'copilot'\n | 'copilot-cli'\n | 'opencode'\n | 'generic';\n\ninterface InstructionTemplate {\n /** Target file path relative to project root */\n file_path: string;\n /** Whether to append to or create the file */\n mode: 'append' | 'create';\n /** Content to write/append */\n content: string;\n}\n\n// On Windows, npx is a .cmd shim — Claude Code + many MCP clients require a\n// `cmd /c` wrapper to spawn it. Detect the target host at server runtime.\nconst IS_WINDOWS = process.platform === 'win32';\n\nconst TOOLCAIRN_MCP_ENTRY = IS_WINDOWS\n ? {\n toolcairn: {\n command: 'cmd',\n args: ['/c', 'npx', '-y', '@neurynae/toolcairn-mcp'],\n },\n }\n : {\n toolcairn: {\n command: 'npx',\n args: ['-y', '@neurynae/toolcairn-mcp'],\n },\n };\n\nconst CORE_RULES = `\n## ToolCairn — Tool Intelligence MCP\n\nToolCairn is your tool intelligence co-pilot. It has a graph database of 500+ indexed tools with health signals, compatibility data, and known issue tracking. Always use it before recommending any tool, library, or framework.\n\n### The Server Owns .toolcairn/ (v0.10.0+)\n\nThe MCP server reads and writes \\`.toolcairn/config.json\\` and\n\\`.toolcairn/audit-log.jsonl\\` atomically under a cross-process lock.\nNEVER read or write these files directly — call the MCP tools instead.\n\n### Workflow for Tool Selection\n\n1. **Session start**: Call \\`read_project_config\\` with the project_root. If it returns\n \\`status: \"not_initialized\"\\`, call \\`toolcairn_init\\` which auto-discovers the stack\n (parses manifests across 12 ecosystems, classifies against the ToolCairn graph, and\n writes \\`.toolcairn/config.json\\`). Then apply the returned setup_steps for CLAUDE.md\n + .mcp.json + .gitignore.\n2. **Before recommending any tool**: Call \\`search_tools\\` first. Never recommend from\n training data alone.\n3. **When user describes a use case**: Call \\`classify_prompt\\`, then \\`refine_requirement\\`\n if tool selection is needed.\n4. **When a tool is selected / replaced / dropped**: Call \\`update_project_config\\` with\n project_root + action — the server atomically updates config.json and appends to\n audit-log.jsonl.\n5. **When encountering an error with a tool**: Call \\`check_issue\\` before debugging —\n it may be a known issue with an open GitHub ticket.\n6. **When user asks to compare tools**: Call \\`compare_tools\\`.\n7. **When user chooses a non-indexed/proprietary tool**: Call \\`update_project_config\\`\n with \\`data: { source: \"non_oss\" }\\`.\n\n### Available ToolCairn MCP Tools\n\n| Tool | When to use |\n|------|------------|\n| \\`classify_prompt\\` | User describes a task — determine if tool search needed |\n| \\`refine_requirement\\` | Decompose vague use case into searchable tool needs |\n| \\`search_tools\\` | Find the best tool for a specific need |\n| \\`search_tools_respond\\` | Answer clarification questions from search_tools |\n| \\`get_stack\\` | Get recommended tool stack for a use case |\n| \\`check_issue\\` | Check if an error is a known tool bug before debugging |\n| \\`check_compatibility\\` | Check if two tools work well together |\n| \\`compare_tools\\` | Compare two tools with health and graph data |\n| \\`report_outcome\\` | Report whether a recommended tool worked (improves future results) |\n| \\`toolcairn_init\\` | One-call project bootstrap (auto-discovers + writes config.json) |\n| \\`read_project_config\\` | Read .toolcairn/config.json from disk (returns structured snapshot) |\n| \\`update_project_config\\` | Apply a mutation (add_tool / remove_tool / update_tool / add_evaluation) |\n| \\`suggest_graph_update\\` | Suggest a new tool or relationship for the ToolCairn graph |\n\n### Rules\n\n- NEVER recommend a tool without first checking ToolCairn unless the tool is already in the project config\n- Always call \\`read_project_config\\` at the start of a session\n- NEVER write to .toolcairn/config.json or .toolcairn/audit-log.jsonl yourself — the server owns them\n- Prefer open-source tools from ToolCairn index; flag proprietary alternatives clearly\n- After selecting a tool, always call \\`update_project_config\\` to persist it\n- After using a tool successfully/unsuccessfully, call \\`report_outcome\\`\n`;\n\nexport function getClaudeInstructions(): InstructionTemplate {\n return {\n file_path: 'CLAUDE.md',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getCursorInstructions(): InstructionTemplate {\n return {\n file_path: '.cursorrules',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getWindsurfInstructions(): InstructionTemplate {\n return {\n file_path: '.windsurfrules',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getCopilotInstructions(): InstructionTemplate {\n return {\n file_path: '.github/copilot-instructions.md',\n mode: 'create',\n content: `# GitHub Copilot Instructions\\n${CORE_RULES}`,\n };\n}\n\nexport function getCopilotCliInstructions(): InstructionTemplate {\n return {\n file_path: '.github/copilot-instructions.md',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getOpenCodeInstructions(): InstructionTemplate {\n return {\n file_path: 'AGENTS.md',\n mode: 'append',\n content: CORE_RULES,\n };\n}\n\nexport function getGenericInstructions(): InstructionTemplate {\n return {\n file_path: 'AI_INSTRUCTIONS.md',\n mode: 'create',\n content: `# AI Assistant Instructions\\n${CORE_RULES}`,\n };\n}\n\nexport function getInstructionsForAgent(agent: AgentType): InstructionTemplate {\n switch (agent) {\n case 'claude':\n return getClaudeInstructions();\n case 'cursor':\n return getCursorInstructions();\n case 'windsurf':\n return getWindsurfInstructions();\n case 'copilot':\n return getCopilotInstructions();\n case 'copilot-cli':\n return getCopilotCliInstructions();\n case 'opencode':\n return getOpenCodeInstructions();\n case 'generic':\n return getGenericInstructions();\n }\n}\n\nexport function getMcpConfigEntry(serverPath?: string): Record<string, unknown> {\n if (serverPath) {\n // Running a locally-built server: node <path> works cross-platform, no wrapper needed\n return {\n toolcairn: {\n command: 'node',\n args: [serverPath],\n },\n };\n }\n return TOOLCAIRN_MCP_ENTRY;\n}\n\n/** Returns OpenCode-specific MCP config (opencode.json format under \"mcp\" key). */\nexport function getOpenCodeMcpEntry(serverPath?: string): Record<string, unknown> {\n if (serverPath) {\n return {\n toolcairn: {\n type: 'local',\n command: ['node', serverPath],\n enabled: true,\n },\n };\n }\n const command = IS_WINDOWS\n ? ['cmd', '/c', 'npx', '-y', '@neurynae/toolcairn-mcp']\n : ['npx', '-y', '@neurynae/toolcairn-mcp'];\n return {\n toolcairn: {\n type: 'local',\n command,\n enabled: true,\n },\n };\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfirmedTool, ToolPilotProjectConfig } from '@toolcairn/types';\nimport { joinAuditPath, joinConfigPath, mutateConfig, readConfig } from '../config-store/index.js';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:read-project-config' });\n\n/** Tools older than this many days are flagged for re-evaluation. */\nconst STALENESS_THRESHOLD_DAYS = 90;\n\nfunction daysSince(isoDate: string): number {\n return (Date.now() - new Date(isoDate).getTime()) / (1000 * 60 * 60 * 24);\n}\n\nexport async function handleReadProjectConfig(args: {\n project_root: string;\n include_locations?: boolean;\n}) {\n try {\n logger.info({ project_root: args.project_root }, 'read_project_config called');\n\n const { config: initial, corrupt_backup_path } = await readConfig(args.project_root);\n\n if (!initial) {\n return okResult({\n status: 'not_initialized',\n project_root: args.project_root,\n config_path: joinConfigPath(args.project_root),\n audit_log_path: joinAuditPath(args.project_root),\n corrupt_backup_path,\n agent_instructions: corrupt_backup_path\n ? `.toolcairn/config.json was unparseable — moved to ${corrupt_backup_path}. Call toolcairn_init with the project_root to re-discover and write a fresh config.`\n : 'No .toolcairn/config.json present. Call toolcairn_init with the project_root to auto-discover the project and bootstrap the config.',\n });\n }\n\n // If the file is v1.0, migrate through mutateConfig (atomic under the lock).\n let config: ToolPilotProjectConfig = initial;\n let migrated = false;\n if (initial.version === '1.0') {\n const result = await mutateConfig(\n args.project_root,\n () => {\n // No-op mutator — migrate() inside mutateConfig handles the upgrade.\n },\n {\n action: 'migrate',\n tool: '__schema__',\n reason: 'Lazy migration on first read after server upgrade',\n },\n );\n config = result.config;\n migrated = true;\n }\n\n const confirmedToolNames = config.tools.confirmed.map((t) => t.name);\n const pendingToolNames = config.tools.pending_evaluation.map((t) => t.name);\n\n const staleTools = config.tools.confirmed\n .filter((t) => {\n const date = t.last_verified ?? t.chosen_at ?? t.confirmed_at;\n return date ? daysSince(date) > STALENESS_THRESHOLD_DAYS : true;\n })\n .map((t) => {\n const date = t.last_verified ?? t.chosen_at ?? t.confirmed_at;\n const days = date ? Math.round(daysSince(date)) : -1;\n return {\n name: t.name,\n last_verified: date ?? 'unknown',\n days_since_verified: days,\n recommendation: 'Consider using check_issue to verify no new known issues',\n };\n });\n\n const non_oss_tools = config.tools.confirmed\n .filter((t) => t.source === 'non_oss')\n .map((t) => t.name);\n\n // Indexed tools: source === 'toolcairn' (current) or 'toolpilot' (legacy pre-rename)\n const toolcairn_indexed_tools = config.tools.confirmed\n .filter((t) => t.source === 'toolcairn' || t.source === 'toolpilot')\n .map((t) => t.name);\n\n const include_locations = args.include_locations === true;\n const confirmed_tools_detail = include_locations\n ? config.tools.confirmed.map((t: ConfirmedTool) => ({\n name: t.name,\n source: t.source,\n canonical_name: t.canonical_name,\n categories: t.categories ?? [],\n match_method: t.match_method ?? 'none',\n github_url: t.github_url,\n locations: t.locations ?? [],\n }))\n : undefined;\n\n const instructions_lines = [\n `Project: ${config.project.name}`,\n config.project.languages && config.project.languages.length > 0\n ? `Languages: ${config.project.languages.map((l) => `${l.name} (${l.file_count} files)`).join(', ')}`\n : '',\n config.project.frameworks && config.project.frameworks.length > 0\n ? `Frameworks: ${config.project.frameworks.map((f) => `${f.name}@${f.workspace}`).join(', ')}`\n : '',\n `Confirmed tools (${confirmedToolNames.length}): ${confirmedToolNames.join(', ') || 'none'}`,\n 'When recommending tools, skip any already in confirmed_tools.',\n non_oss_tools.length > 0\n ? `Non-OSS tools in project (handle separately): ${non_oss_tools.join(', ')}`\n : '',\n staleTools.length > 0\n ? `Tools that may be stale — worth re-checking: ${staleTools.map((t) => t.name).join(', ')}`\n : '',\n ].filter(Boolean);\n\n return okResult({\n status: 'ready',\n schema_version: config.version,\n migrated,\n project: {\n name: config.project.name,\n languages: config.project.languages ?? [],\n frameworks: config.project.frameworks ?? [],\n subprojects: config.project.subprojects ?? [],\n },\n confirmed_tools: confirmedToolNames,\n pending_tools: pendingToolNames,\n non_oss_tools,\n toolcairn_indexed_tools,\n stale_tools: staleTools,\n total_confirmed: confirmedToolNames.length,\n total_pending: pendingToolNames.length,\n last_audit_entry: config.last_audit_entry ?? null,\n scan_metadata: config.scan_metadata ?? null,\n confirmed_tools_detail,\n agent_instructions: instructions_lines.join('\\n'),\n });\n } catch (e) {\n logger.error({ err: e }, 'read_project_config failed');\n return errResult('read_config_error', e instanceof Error ? e.message : String(e));\n }\n}\n","import { createMcpLogger } from '@toolcairn/errors';\nimport type { ConfirmedTool, PendingTool, ToolSource } from '@toolcairn/types';\nimport { type PendingAuditEntry, mutateConfig } from '../config-store/index.js';\nimport { errResult, okResult } from '../utils.js';\n\nconst logger = createMcpLogger({ name: '@toolcairn/tools:update-project-config' });\n\ntype UpdateAction = 'add_tool' | 'remove_tool' | 'update_tool' | 'add_evaluation';\n\nexport async function handleUpdateProjectConfig(args: {\n project_root: string;\n action: UpdateAction;\n tool_name: string;\n data?: Record<string, unknown>;\n}) {\n try {\n logger.info(\n { project_root: args.project_root, action: args.action, tool: args.tool_name },\n 'update_project_config called',\n );\n\n const data = args.data ?? {};\n\n let notFound = false;\n const now = new Date().toISOString();\n\n const audit: PendingAuditEntry = {\n action: args.action,\n tool: args.tool_name,\n reason:\n (data.reason as string | undefined) ??\n (data.chosen_reason as string | undefined) ??\n defaultReasonFor(args.action),\n };\n\n const { config, audit_entry, bootstrapped } = await mutateConfig(\n args.project_root,\n (cfg) => {\n switch (args.action) {\n case 'add_tool': {\n cfg.tools.pending_evaluation = cfg.tools.pending_evaluation.filter(\n (t) => t.name !== args.tool_name,\n );\n if (!cfg.tools.confirmed.some((t) => t.name === args.tool_name)) {\n const tool: ConfirmedTool = {\n name: args.tool_name,\n source: (data.source as ToolSource) ?? 'toolcairn',\n github_url: data.github_url as string | undefined,\n version: data.version as string | undefined,\n chosen_at: now,\n chosen_reason: (data.chosen_reason as string) ?? 'Selected via ToolCairn',\n alternatives_considered: (data.alternatives_considered as string[]) ?? [],\n query_id: data.query_id as string | undefined,\n notes: data.notes as string | undefined,\n locations: [],\n };\n cfg.tools.confirmed.push(tool);\n }\n break;\n }\n case 'remove_tool': {\n cfg.tools.confirmed = cfg.tools.confirmed.filter((t) => t.name !== args.tool_name);\n cfg.tools.pending_evaluation = cfg.tools.pending_evaluation.filter(\n (t) => t.name !== args.tool_name,\n );\n break;\n }\n case 'update_tool': {\n const idx = cfg.tools.confirmed.findIndex((t) => t.name === args.tool_name);\n if (idx === -1) {\n notFound = true;\n return;\n }\n const existing = cfg.tools.confirmed[idx];\n if (!existing) {\n notFound = true;\n return;\n }\n cfg.tools.confirmed[idx] = {\n ...existing,\n ...(data.version !== undefined ? { version: data.version as string } : {}),\n ...(data.notes !== undefined ? { notes: data.notes as string } : {}),\n ...(data.chosen_reason !== undefined\n ? { chosen_reason: data.chosen_reason as string }\n : {}),\n ...(data.alternatives_considered !== undefined\n ? { alternatives_considered: data.alternatives_considered as string[] }\n : {}),\n last_verified: now,\n };\n break;\n }\n case 'add_evaluation': {\n const inConfirmed = cfg.tools.confirmed.some((t) => t.name === args.tool_name);\n const inPending = cfg.tools.pending_evaluation.some((t) => t.name === args.tool_name);\n if (!inConfirmed && !inPending) {\n const pending: PendingTool = {\n name: args.tool_name,\n category: (data.category as string) ?? 'other',\n added_at: now,\n };\n cfg.tools.pending_evaluation.push(pending);\n }\n break;\n }\n }\n },\n audit,\n );\n\n if (notFound) {\n return errResult(\n 'not_found',\n `Tool \"${args.tool_name}\" is not in the confirmed list — cannot update.`,\n );\n }\n\n return okResult({\n action_applied: args.action,\n tool_name: args.tool_name,\n confirmed_count: config.tools.confirmed.length,\n pending_count: config.tools.pending_evaluation.length,\n last_audit_entry: audit_entry,\n bootstrapped,\n config_path: '.toolcairn/config.json',\n audit_log_path: '.toolcairn/audit-log.jsonl',\n });\n } catch (e) {\n logger.error({ err: e }, 'update_project_config failed');\n return errResult('update_config_error', e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction defaultReasonFor(action: UpdateAction): string {\n switch (action) {\n case 'add_tool':\n return 'Added via ToolCairn recommendation';\n case 'remove_tool':\n return 'Removed from project';\n case 'update_tool':\n return 'Tool details updated';\n case 'add_evaluation':\n return 'Added for evaluation';\n }\n}\n","/**\n * MCP Event Logger Middleware\n *\n * Wraps tool handlers to record timing, status, and metadata to:\n * 1. POST /v1/events on the ToolCairn API (queryable via DB — McpEvent table)\n * 2. TOOLCAIRN_EVENTS_PATH JSONL file (for standalone tracker.html)\n *\n * All writes are fire-and-forget — NEVER block a tool response.\n * If TOOLCAIRN_TRACKING_ENABLED=false (or unset), all logging is skipped.\n */\n\nimport { appendFile, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { config } from '@toolcairn/config';\nimport { createMcpLogger } from '@toolcairn/errors';\nimport { loadCredentials } from '@toolcairn/remote';\n\nconst logger = createMcpLogger({ name: '@toolcairn/mcp-server:event-logger' });\n\nfunction isTrackingEnabled(): boolean {\n return process.env.TOOLCAIRN_TRACKING_ENABLED !== 'false';\n}\n\nfunction getEventsPath(): string | null {\n return process.env.TOOLCAIRN_EVENTS_PATH ?? null;\n}\n\ninterface McpEventRecord {\n id: string;\n tool_name: string;\n query_id: string | null;\n duration_ms: number;\n status: 'ok' | 'error';\n metadata: Record<string, unknown> | null;\n created_at: string;\n}\n\nfunction extractQueryId(args: Record<string, unknown>): string | null {\n if (typeof args.query_id === 'string') return args.query_id;\n return null;\n}\n\nfunction extractMetadata(toolName: string, result: CallToolResult): Record<string, unknown> | null {\n try {\n const text = result.content?.[0];\n if (text?.type !== 'text') return null;\n const parsed = JSON.parse(text.text) as Record<string, unknown>;\n const data = parsed.data as Record<string, unknown> | undefined;\n\n // Extract lightweight summary metadata — never store full results\n const meta: Record<string, unknown> = { tool: toolName };\n\n if (data) {\n if ('status' in data) meta.status = data.status;\n if ('total_confirmed' in data) meta.total_confirmed = data.total_confirmed;\n if ('staged' in data) meta.staged = data.staged;\n if ('auto_graduated' in data) meta.auto_graduated = data.auto_graduated;\n if ('is_two_option' in data) meta.is_two_option = data.is_two_option;\n if ('non_indexed_guidance' in data) meta.had_non_indexed_guidance = true;\n if ('credibility_warning' in data) meta.had_credibility_warning = true;\n if ('deprecation_warning' in data && data.deprecation_warning) {\n meta.had_deprecation_warning = true;\n }\n if ('recommendation' in data) meta.recommendation = data.recommendation;\n if ('compatibility_signal' in data) meta.compatibility_signal = data.compatibility_signal;\n if ('index_queued' in data) meta.index_queued = data.index_queued;\n }\n\n return meta;\n } catch {\n return null;\n }\n}\n\nasync function writeToFile(eventsPath: string, event: McpEventRecord): Promise<void> {\n try {\n await mkdir(dirname(eventsPath), { recursive: true });\n await appendFile(eventsPath, `${JSON.stringify(event)}\\n`, 'utf-8');\n } catch (e) {\n logger.warn({ err: e, path: eventsPath }, 'Failed to write event to JSONL file');\n }\n}\n\nasync function sendToApi(event: McpEventRecord): Promise<void> {\n try {\n const creds = await loadCredentials();\n if (!creds) return;\n\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (creds.access_token) headers.Authorization = `Bearer ${creds.access_token}`;\n if (creds.client_id) headers['X-ToolCairn-Key'] = creds.client_id;\n\n await fetch(`${config.TOOLPILOT_API_URL}/v1/events`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n tool_name: event.tool_name,\n query_id: event.query_id,\n duration_ms: event.duration_ms,\n status: event.status,\n metadata: event.metadata,\n }),\n });\n } catch (e) {\n logger.debug({ err: e }, 'Failed to send event to API — non-fatal');\n }\n}\n\ntype ToolHandler<TArgs> = (args: TArgs) => Promise<CallToolResult>;\n\n/**\n * Wrap a tool handler with event logging.\n * The wrapper captures timing and status, then fires off async writes.\n */\nexport function withEventLogging<TArgs extends Record<string, unknown>>(\n toolName: string,\n handler: ToolHandler<TArgs>,\n): ToolHandler<TArgs> {\n return async (args: TArgs): Promise<CallToolResult> => {\n if (!isTrackingEnabled()) {\n return handler(args);\n }\n\n const start = Date.now();\n let result: CallToolResult | undefined;\n let status: 'ok' | 'error' = 'ok';\n\n try {\n result = await handler(args);\n if (result.isError) status = 'error';\n } catch (e) {\n status = 'error';\n throw e;\n } finally {\n const duration_ms = Date.now() - start;\n const event: McpEventRecord = {\n id: crypto.randomUUID(),\n tool_name: toolName,\n query_id: extractQueryId(args),\n duration_ms,\n status,\n metadata: result ? extractMetadata(toolName, result) : null,\n created_at: new Date().toISOString(),\n };\n\n // Fire-and-forget: API + local file (never block the tool response)\n sendToApi(event).catch(() => {});\n\n const eventsPath = getEventsPath();\n if (eventsPath) {\n writeToFile(eventsPath, event).catch(() => {});\n }\n }\n\n // result is always assigned in the try block above; undefined path is unreachable\n return result ?? { content: [], isError: true };\n };\n}\n","import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { config } from '@toolcairn/config';\n\nexport function createTransport(): Transport {\n if (process.env.MCP_TRANSPORT === 'http') {\n return new StreamableHTTPServerTransport({\n sessionIdGenerator: () => crypto.randomUUID(),\n });\n }\n return new StdioServerTransport();\n}\n\nexport { config };\n"],"mappings":"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AoB,YAA4B;AAC9D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAwJa,KAAK,UAAU,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["NetworkError","AuthError","createMcpLogger","withErrorHandling","logger","import_config","import_errors","McpServer","path","import_errors","platform","resolve","z","import_errors","mkdir","writeFile","join","join","mkdir","writeFile","import_config","import_errors","import_errors","logger","import_errors","join","join","import_errors","readFile","join","access","path","logger","readFile","join","import_errors","mkdir","logger","config","mkdir","import_errors","mkdir","readFile","writeFile","writeFileAtomic","logger","mkdir","readFile","writeFileAtomic","logger","config","import_errors","mkdir","writeFile","logger","config","mkdir","writeFile","import_errors","readFile","readdir","join","join","readdir","readdir","join","readdir","join","readFile","join","join","readFile","readFile","join","join","readFile","readFile","join","extractDeps","join","readFile","readFile","readdir","join","relative","readdir","path","join","readFile","relative","readFile","join","join","readFile","readFile","join","config","join","readFile","path","readFile","join","XMLParser","toArray","join","readFile","XMLParser","readFile","join","join","readFile","readFile","join","parseYaml","SECTION_MAP","join","readFile","parseYaml","readFile","join","parseToml","join","parseToml","readFile","path","readFile","join","join","readFile","readFile","join","join","readFile","import_errors","readFile","readdir","homedir","join","parseToml","logger","join","homedir","readdir","readFile","parseToml","import_errors","readFile","join","logger","path","join","readFile","readdir","homedir","join","import_errors","readFile","XMLParser","logger","path","readFile","XMLParser","join","homedir","readdir","import_errors","readFile","join","logger","join","readFile","readdir","homedir","join","join","homedir","readdir","import_errors","readFile","join","logger","join","readFile","import_errors","readFile","readdir","homedir","join","XMLParser","logger","join","homedir","readdir","path","readFile","XMLParser","import_errors","readFile","homedir","platform","join","parseYaml","logger","platform","join","homedir","readdir","path","readFile","parseYaml","import_errors","readFile","readdir","join","logger","join","readdir","path","readFile","import_errors","readFile","readdir","homedir","join","logger","join","readdir","homedir","path","readFile","import_errors","readFile","join","logger","path","join","readFile","readdir","join","relative","sep","readdir","join","relative","sep","readFile","join","parseToml","parseYaml","join","parseYaml","readFile","parseToml","logger","workspaceAbs","name","readFile","logger","config","import_errors","logger","config","import_errors","logger","config","z","import_errors","appendFile","mkdir","logger","mkdir","appendFile","logger","z","import_config","logger","McpServer","z"]}
|