rulesync 13.0.0 → 14.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["parseToolTarget","record","SKILL_FILE_NAME","SKILL_FILE_NAME","RULESYNC_CONTENT_HASH_REGEX","computeContentHash","RULESYNC_CONTENT_HASH_REGEX","existing","assertFrozenLockCoversSources","SKILL_FILE_NAME","logger","logger","executeConvert","buildSuccessResponse","executeGenerate","buildSuccessResponse","executeImport","logger","logger","SKILL_FILE_NAME","os","path","wrapCommand","_wrapCommand"],"sources":["../../src/utils/parse-comma-separated-list.ts","../../src/utils/result.ts","../../src/cli/commands/convert.ts","../../src/types/fetch-targets.ts","../../src/types/fetch.ts","../../src/lib/github-client.ts","../../src/lib/github-utils.ts","../../src/types/git-provider.ts","../../src/lib/source-parser.ts","../../src/lib/fetch.ts","../../src/cli/commands/fetch.ts","../../src/cli/commands/generate.ts","../../src/cli/commands/gitignore-derive.ts","../../src/cli/commands/gitignore-entries.ts","../../src/cli/commands/gitignore.ts","../../src/cli/commands/import.ts","../../src/lib/init.ts","../../src/cli/commands/init.ts","../../src/lib/apm/apm-lock.ts","../../src/lib/apm/apm-manifest.ts","../../src/lib/apm/apm-install.ts","../../src/lib/gh/gh-frontmatter.ts","../../src/lib/gh/gh-lock.ts","../../src/lib/gh/gh-paths.ts","../../src/lib/gh/gh-install.ts","../../src/lib/git-client.ts","../../src/lib/sources-lock.ts","../../src/lib/sources.ts","../../src/cli/commands/install.ts","../../src/mcp/checks.ts","../../src/mcp/commands.ts","../../src/mcp/convert.ts","../../src/mcp/generate.ts","../../src/mcp/hooks.ts","../../src/mcp/ignore.ts","../../src/mcp/import.ts","../../src/mcp/mcp.ts","../../src/mcp/permissions.ts","../../src/mcp/rules.ts","../../src/mcp/skills.ts","../../src/mcp/subagents.ts","../../src/mcp/tools.ts","../../src/cli/commands/mcp.ts","../../src/cli/commands/resolve-gitignore-targets.ts","../../src/lib/update.ts","../../src/cli/commands/update.ts","../../src/cli/wrap-command.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * Parses a comma-separated string into a trimmed, non-empty array of strings.\n *\n * Handles trailing commas and extra whitespace gracefully.\n *\n * @example\n * parseCommaSeparatedList(\"a, b, c\") // => [\"a\", \"b\", \"c\"]\n * parseCommaSeparatedList(\"a,,b,\") // => [\"a\", \"b\"]\n */\nexport const parseCommaSeparatedList = (value: string): string[] =>\n value\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n","/**\n * Result of writing AI files, including both count and file paths\n */\nexport type WriteResult = {\n count: number;\n paths: string[];\n};\n\n/**\n * Result of feature generation, extending WriteResult with hasDiff\n */\nexport type FeatureGenerateResult = WriteResult & { hasDiff: boolean };\n\n/**\n * Common count fields shared by ImportResult and GenerateResult\n */\nexport type CountableResult = {\n rulesCount: number;\n ignoreCount: number;\n mcpCount: number;\n commandsCount: number;\n subagentsCount: number;\n skillsCount: number;\n hooksCount: number;\n permissionsCount: number;\n checksCount: number;\n};\n\n/**\n * Calculate the total count from a result object\n */\nexport function calculateTotalCount(result: CountableResult): number {\n return (\n result.rulesCount +\n result.ignoreCount +\n result.mcpCount +\n result.commandsCount +\n result.subagentsCount +\n result.skillsCount +\n result.hooksCount +\n result.permissionsCount +\n result.checksCount\n );\n}\n","import { ConfigResolver, ConfigResolverResolveParams } from \"../../config/config-resolver.js\";\nimport { convertFromTool } from \"../../lib/convert.js\";\nimport type { RulesyncFeatures } from \"../../types/features.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport { ALL_TOOL_TARGETS, type ToolTarget, ToolTargetSchema } from \"../../types/tool-targets.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { calculateTotalCount } from \"../../utils/result.js\";\n\nexport type ConvertOptions = Omit<\n ConfigResolverResolveParams,\n \"delete\" | \"outputRoots\" | \"targets\"\n> & {\n from?: string;\n to?: string[];\n features?: RulesyncFeatures;\n};\n\nfunction parseToolTarget(value: string, label: string): ToolTarget {\n const result = ToolTargetSchema.safeParse(value);\n if (!result.success) {\n throw new CLIError(\n `Invalid ${label} tool '${value}'. Must be one of: ${ALL_TOOL_TARGETS.join(\", \")}`,\n ErrorCodes.CONVERT_FAILED,\n );\n }\n return result.data;\n}\n\nexport async function convertCommand(logger: Logger, options: ConvertOptions): Promise<void> {\n // `--from` and `--to` presence is enforced by commander's `requiredOption`\n // in `src/cli/index.ts`; here we only need to validate the tool names.\n const fromTool = parseToolTarget(options.from ?? \"\", \"source\");\n const toToolsRaw = (options.to ?? []).map((t) => parseToolTarget(t, \"destination\"));\n const toTools = Array.from(new Set(toToolsRaw));\n\n if (toTools.includes(fromTool)) {\n throw new CLIError(\n `Destination tools must not include the source tool '${fromTool}'. ` +\n `Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`,\n ErrorCodes.CONVERT_FAILED,\n );\n }\n\n // Pass both source and destinations as `targets` so per-target feature maps\n // in `rulesync.jsonc` are honored for every tool involved. Default features\n // to `*` so every feature that both tools support is attempted.\n const config = await ConfigResolver.resolve({\n ...options,\n targets: [fromTool, ...toTools],\n features: options.features ?? [\"*\"],\n });\n\n const isPreview = config.isPreviewMode();\n const modePrefix = isPreview ? \"[DRY RUN] \" : \"\";\n\n logger.debug(`Converting files from ${fromTool} to ${toTools.join(\", \")}...`);\n\n const result = await convertFromTool({ config, fromTool, toTools, logger });\n\n const totalConverted = calculateTotalCount(result);\n\n if (totalConverted === 0) {\n const enabledFeatures = config.getFeatures(fromTool).join(\", \");\n logger.warn(`No files converted for enabled features: ${enabledFeatures}`);\n return;\n }\n\n if (logger.jsonMode) {\n logger.captureData(\"from\", fromTool);\n logger.captureData(\"to\", toTools);\n logger.captureData(\"dryRun\", isPreview);\n logger.captureData(\"features\", {\n rules: { count: result.rulesCount },\n ignore: { count: result.ignoreCount },\n mcp: { count: result.mcpCount },\n commands: { count: result.commandsCount },\n subagents: { count: result.subagentsCount },\n skills: { count: result.skillsCount },\n hooks: { count: result.hooksCount },\n permissions: { count: result.permissionsCount },\n checks: { count: result.checksCount },\n });\n logger.captureData(\"totalFiles\", totalConverted);\n }\n\n const parts: string[] = [];\n if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);\n if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);\n if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);\n if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);\n if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);\n if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);\n if (result.hooksCount > 0) parts.push(`${result.hooksCount} hooks`);\n if (result.permissionsCount > 0) parts.push(`${result.permissionsCount} permissions`);\n if (result.checksCount > 0) parts.push(`${result.checksCount} checks`);\n\n const verbPhrase = isPreview ? \"Would convert\" : \"Converted\";\n const summary = `${modePrefix}${verbPhrase} ${totalConverted} file(s) total from ${fromTool} to ${toTools.join(\", \")} (${parts.join(\" + \")})`;\n\n if (isPreview) {\n logger.info(summary);\n } else {\n logger.success(summary);\n }\n}\n","import { z } from \"zod/mini\";\n\nimport { ALL_TOOL_TARGETS } from \"./tool-targets.js\";\n\n/**\n * Fetch command targets for specifying file format interpretation\n * - \"rulesync\": rulesync format with frontmatter containing targets, description, etc.\n * - Tool targets: interpreted as tool-specific format (e.g., claudecode, cursor)\n */\nconst ALL_FETCH_TARGETS = [\"rulesync\", ...ALL_TOOL_TARGETS] as const;\n\nexport const FetchTargetSchema = z.enum(ALL_FETCH_TARGETS);\n\nexport type FetchTarget = z.infer<typeof FetchTargetSchema>;\n","import { z } from \"zod/mini\";\n\nimport { ALL_FEATURES_WITH_WILDCARD } from \"./features.js\";\nimport { FetchTargetSchema } from \"./fetch-targets.js\";\nimport type { GitProvider } from \"./git-provider.js\";\n\n/**\n * Conflict resolution strategies for fetch command\n */\nconst ConflictStrategySchema = z.enum([\"skip\", \"overwrite\"]);\nexport type ConflictStrategy = z.infer<typeof ConflictStrategySchema>;\n\n/**\n * GitHub file type from API response\n */\nconst GitHubFileTypeSchema = z.enum([\"file\", \"dir\", \"symlink\", \"submodule\"]);\n\n/**\n * GitHub file/directory entry from contents API\n */\nexport const GitHubFileEntrySchema = z.looseObject({\n name: z.string(),\n path: z.string(),\n sha: z.string(),\n size: z.number(),\n type: GitHubFileTypeSchema,\n download_url: z.nullable(z.string()),\n});\nexport type GitHubFileEntry = z.infer<typeof GitHubFileEntrySchema>;\n\n/**\n * Parsed source specification for fetch command\n */\nexport type ParsedSource = {\n provider: GitProvider;\n owner: string;\n repo: string;\n ref?: string;\n path?: string;\n};\n\n/**\n * Fetch command options\n */\nconst FetchOptionsSchema = z.looseObject({\n target: z.optional(FetchTargetSchema),\n features: z.optional(z.array(z.enum(ALL_FEATURES_WITH_WILDCARD))),\n ref: z.optional(z.string()),\n path: z.optional(z.string()),\n output: z.optional(z.string()),\n conflict: z.optional(ConflictStrategySchema),\n token: z.optional(z.string()),\n verbose: z.optional(z.boolean()),\n silent: z.optional(z.boolean()),\n});\nexport type FetchOptions = z.infer<typeof FetchOptionsSchema>;\n\n/**\n * Result status for a single file fetch operation\n */\nconst FetchFileStatusSchema = z.enum([\"created\", \"overwritten\", \"skipped\"]);\ntype FetchFileStatus = z.infer<typeof FetchFileStatusSchema>;\n\n/**\n * Result of a single file fetch operation\n */\nexport type FetchFileResult = {\n relativePath: string;\n status: FetchFileStatus;\n};\n\n/**\n * Summary of fetch operation\n */\nexport type FetchSummary = {\n source: string;\n ref: string;\n files: FetchFileResult[];\n created: number;\n overwritten: number;\n skipped: number;\n};\n\n/**\n * GitHub API error response\n */\nexport type GitHubApiError = {\n message: string;\n documentation_url?: string;\n};\n\n/**\n * Configuration for GitHub client\n */\nexport type GitHubClientConfig = {\n token?: string;\n baseUrl?: string;\n};\n\n/**\n * Repository information from GitHub API\n */\nexport const GitHubRepoInfoSchema = z.looseObject({\n default_branch: z.string(),\n private: z.boolean(),\n});\nexport type GitHubRepoInfo = z.infer<typeof GitHubRepoInfoSchema>;\n\n/**\n * GitHub release asset from releases API\n */\nconst GitHubReleaseAssetSchema = z.looseObject({\n name: z.string(),\n browser_download_url: z.string(),\n size: z.number(),\n});\nexport type GitHubReleaseAsset = z.infer<typeof GitHubReleaseAssetSchema>;\n\n/**\n * GitHub release from releases API\n */\nexport const GitHubReleaseSchema = z.looseObject({\n tag_name: z.string(),\n name: z.nullable(z.string()),\n prerelease: z.boolean(),\n draft: z.boolean(),\n assets: z.array(GitHubReleaseAssetSchema),\n});\nexport type GitHubRelease = z.infer<typeof GitHubReleaseSchema>;\n","import { RequestError } from \"@octokit/request-error\";\nimport { Octokit } from \"@octokit/rest\";\n\nimport { MAX_FILE_SIZE } from \"../constants/rulesync-paths.js\";\nimport type {\n GitHubApiError,\n GitHubClientConfig,\n GitHubFileEntry,\n GitHubRelease,\n GitHubRepoInfo,\n} from \"../types/fetch.js\";\nimport {\n GitHubFileEntrySchema,\n GitHubReleaseSchema,\n GitHubRepoInfoSchema,\n} from \"../types/fetch.js\";\nimport { formatError } from \"../utils/error.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/**\n * Error class for GitHub API errors\n */\nexport class GitHubClientError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly apiError?: GitHubApiError,\n ) {\n super(message);\n this.name = \"GitHubClientError\";\n }\n}\n\n/**\n * Log GitHub auth error hints for 401/403 responses.\n */\nexport function logGitHubAuthHints(params: { error: GitHubClientError; logger: Logger }): void {\n const { error, logger } = params;\n logger.error(`GitHub API Error: ${error.message}`);\n if (error.statusCode === 401 || error.statusCode === 403) {\n logger.info(\n \"Tip: Set GITHUB_TOKEN or GH_TOKEN environment variable for private repositories or better rate limits.\",\n );\n logger.info(\n \"Tip: If you use GitHub CLI, you can use `GITHUB_TOKEN=$(gh auth token) rulesync fetch ...`\",\n );\n }\n}\n\n/**\n * Client for interacting with GitHub API using Octokit SDK\n */\nexport class GitHubClient {\n private readonly octokit: Octokit;\n private readonly hasToken: boolean;\n\n constructor(config: GitHubClientConfig = {}) {\n // Validate custom baseUrl uses HTTPS to prevent token exposure\n if (config.baseUrl && !config.baseUrl.startsWith(\"https://\")) {\n throw new GitHubClientError(\"GitHub API base URL must use HTTPS\");\n }\n\n this.hasToken = !!config.token;\n this.octokit = new Octokit({\n auth: config.token,\n baseUrl: config.baseUrl,\n });\n }\n\n /**\n * Get authentication token from various sources\n */\n static resolveToken(explicitToken?: string): string | undefined {\n if (explicitToken) {\n return explicitToken;\n }\n return process.env[\"GITHUB_TOKEN\"] ?? process.env[\"GH_TOKEN\"];\n }\n\n /**\n * Get the default branch of a repository\n */\n async getDefaultBranch(owner: string, repo: string): Promise<string> {\n const repoInfo = await this.getRepoInfo(owner, repo);\n return repoInfo.default_branch;\n }\n\n /**\n * Get repository information\n */\n async getRepoInfo(owner: string, repo: string): Promise<GitHubRepoInfo> {\n try {\n const { data } = await this.octokit.repos.get({ owner, repo });\n const parsed = GitHubRepoInfoSchema.safeParse(data);\n if (!parsed.success) {\n throw new GitHubClientError(\n `Invalid repository info response: ${formatError(parsed.error)}`,\n );\n }\n return parsed.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * List contents of a directory in a repository\n */\n async listDirectory(\n owner: string,\n repo: string,\n path: string,\n ref?: string,\n ): Promise<GitHubFileEntry[]> {\n try {\n const { data } = await this.octokit.repos.getContent({\n owner,\n repo,\n path,\n ref,\n });\n\n // API returns single object for files, array for directories\n if (!Array.isArray(data)) {\n throw new GitHubClientError(`Path \"${path}\" is not a directory`);\n }\n\n const entries: GitHubFileEntry[] = [];\n for (const item of data) {\n const parsed = GitHubFileEntrySchema.safeParse(item);\n if (parsed.success) {\n entries.push(parsed.data);\n }\n }\n return entries;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Get raw file content from a repository\n */\n async getFileContent(owner: string, repo: string, path: string, ref?: string): Promise<string> {\n try {\n const { data } = await this.octokit.repos.getContent({\n owner,\n repo,\n path,\n ref,\n mediaType: {\n format: \"raw\",\n },\n });\n\n // When using raw format, data is returned as a string\n if (typeof data === \"string\") {\n return data;\n }\n\n // Fallback: if data is an object with content (base64 encoded)\n if (!Array.isArray(data) && \"content\" in data && data.content) {\n return Buffer.from(data.content, \"base64\").toString(\"utf-8\");\n }\n\n throw new GitHubClientError(`Unexpected response format for file content`);\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Check if a file exists and is within size limits\n */\n async getFileInfo(\n owner: string,\n repo: string,\n path: string,\n ref?: string,\n ): Promise<GitHubFileEntry | null> {\n try {\n const { data } = await this.octokit.repos.getContent({\n owner,\n repo,\n path,\n ref,\n });\n\n // Ensure it's a file, not a directory\n if (Array.isArray(data)) {\n return null; // It's a directory\n }\n\n const parsed = GitHubFileEntrySchema.safeParse(data);\n if (!parsed.success) {\n return null;\n }\n\n if (parsed.data.size > MAX_FILE_SIZE) {\n throw new GitHubClientError(\n `File \"${path}\" exceeds maximum size limit of ${MAX_FILE_SIZE / 1024 / 1024}MB`,\n );\n }\n\n return parsed.data;\n } catch (error: unknown) {\n if (error instanceof RequestError && error.status === 404) {\n return null;\n }\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return null;\n }\n throw this.handleError(error);\n }\n }\n\n /**\n * Validate that a repository exists and is accessible\n */\n async validateRepository(owner: string, repo: string): Promise<boolean> {\n try {\n await this.getRepoInfo(owner, repo);\n return true;\n } catch (error) {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Resolve a ref (branch, tag, or SHA) to a full commit SHA.\n */\n async resolveRefToSha(owner: string, repo: string, ref: string): Promise<string> {\n try {\n const { data } = await this.octokit.repos.getCommit({\n owner,\n repo,\n ref,\n });\n return data.sha;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Get the latest release from a repository\n */\n async getLatestRelease(owner: string, repo: string): Promise<GitHubRelease> {\n try {\n const { data } = await this.octokit.repos.getLatestRelease({ owner, repo });\n const parsed = GitHubReleaseSchema.safeParse(data);\n if (!parsed.success) {\n throw new GitHubClientError(`Invalid release info response: ${formatError(parsed.error)}`);\n }\n return parsed.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Handle errors from Octokit and convert to GitHubClientError\n */\n private handleError(error: unknown): GitHubClientError {\n if (error instanceof GitHubClientError) {\n return error;\n }\n\n if (error instanceof RequestError) {\n const responseData = error.response?.data;\n const message = this.extractErrorMessage(responseData, error.message);\n const apiError: GitHubApiError | undefined = message ? { message } : undefined;\n const errorMessage = this.getErrorMessage(error.status, apiError);\n return new GitHubClientError(errorMessage, error.status, apiError);\n }\n\n if (error instanceof Error) {\n return new GitHubClientError(error.message);\n }\n\n return new GitHubClientError(\"Unknown error occurred\");\n }\n\n /**\n * Extract error message from response data\n */\n private extractErrorMessage(data: unknown, fallback: string): string {\n if (typeof data === \"object\" && data !== null && \"message\" in data) {\n const record = data as Record<string, unknown>;\n const msg = record[\"message\"];\n if (typeof msg === \"string\") {\n return msg;\n }\n }\n return fallback;\n }\n\n /**\n * Get human-readable error message for HTTP status codes\n */\n private getErrorMessage(statusCode: number, apiError?: GitHubApiError): string {\n const baseMessage = apiError?.message ?? `HTTP ${statusCode}`;\n\n switch (statusCode) {\n case 401:\n return `Authentication failed: ${baseMessage}. Check your GitHub token.`;\n case 403:\n if (baseMessage.toLowerCase().includes(\"rate limit\")) {\n return `GitHub API rate limit exceeded. ${this.hasToken ? \"Try again later.\" : \"Consider using a GitHub token.\"}`;\n }\n return `Access forbidden: ${baseMessage}. Check repository permissions.`;\n case 404:\n return `Not found: ${baseMessage}`;\n case 422:\n return `Invalid request: ${baseMessage}`;\n default:\n return `GitHub API error: ${baseMessage}`;\n }\n }\n}\n","import { Semaphore } from \"es-toolkit/promise\";\n\nimport type { GitHubFileEntry } from \"../types/fetch.js\";\nimport type { GitHubClient } from \"./github-client.js\";\n\nconst MAX_RECURSION_DEPTH = 15;\n\n/**\n * Execute an async function with semaphore-controlled concurrency.\n * Ensures the semaphore permit is always released, even if the function throws.\n */\nexport async function withSemaphore<T>(semaphore: Semaphore, fn: () => Promise<T>): Promise<T> {\n await semaphore.acquire();\n try {\n return await fn();\n } finally {\n semaphore.release();\n }\n}\n\n/**\n * Recursively list all files in a GitHub directory.\n */\nexport async function listDirectoryRecursive(params: {\n client: GitHubClient;\n owner: string;\n repo: string;\n path: string;\n ref?: string;\n depth?: number;\n semaphore: Semaphore;\n}): Promise<GitHubFileEntry[]> {\n const { client, owner, repo, path, ref, depth = 0, semaphore } = params;\n\n if (depth > MAX_RECURSION_DEPTH) {\n throw new Error(\n `Maximum recursion depth (${MAX_RECURSION_DEPTH}) exceeded while listing directory: ${path}`,\n );\n }\n\n // Semaphore is released here before recursive Promise.all below to avoid deadlock\n const entries = await withSemaphore(semaphore, () =>\n client.listDirectory(owner, repo, path, ref),\n );\n\n const files: GitHubFileEntry[] = [];\n const directories: GitHubFileEntry[] = [];\n\n for (const entry of entries) {\n if (entry.type === \"file\") {\n files.push(entry);\n } else if (entry.type === \"dir\") {\n directories.push(entry);\n }\n }\n\n const subResults = await Promise.all(\n directories.map((dir) =>\n listDirectoryRecursive({\n client,\n owner,\n repo,\n path: dir.path,\n ref,\n depth: depth + 1,\n semaphore,\n }),\n ),\n );\n\n return [...files, ...subResults.flat()];\n}\n","import { z } from \"zod/mini\";\n\n/**\n * Supported Git providers for fetch command\n */\nexport const ALL_GIT_PROVIDERS = [\"github\", \"gitlab\"] as const;\n\nconst GitProviderSchema = z.enum(ALL_GIT_PROVIDERS);\n\nexport type GitProvider = z.infer<typeof GitProviderSchema>;\n","import type { ParsedSource } from \"../types/fetch.js\";\nimport type { GitProvider } from \"../types/git-provider.js\";\nimport { ALL_GIT_PROVIDERS } from \"../types/git-provider.js\";\n\nconst GITHUB_HOSTS = new Set([\"github.com\", \"www.github.com\"]);\nconst GITLAB_HOSTS = new Set([\"gitlab.com\", \"www.gitlab.com\"]);\n\n/**\n * Parse source specification into components\n * Supports:\n * - URL format: https://github.com/owner/repo, https://gitlab.com/owner/repo\n * - Prefix format: github:owner/repo, gitlab:owner/repo\n * - Shorthand format: owner/repo (defaults to GitHub)\n * - With ref: owner/repo@ref\n * - With path: owner/repo:path\n * - Combined: owner/repo@ref:path\n */\nexport function parseSource(source: string): ParsedSource {\n // Handle full URL format (https://...)\n if (source.startsWith(\"http://\") || source.startsWith(\"https://\")) {\n return parseUrl(source);\n }\n\n // Handle prefix format (github:owner/repo, gitlab:owner/repo)\n if (source.includes(\":\") && !source.includes(\"://\")) {\n const colonIndex = source.indexOf(\":\");\n const prefix = source.substring(0, colonIndex);\n const rest = source.substring(colonIndex + 1);\n\n // Check if prefix is a known provider using type guard\n const provider = ALL_GIT_PROVIDERS.find((p) => p === prefix);\n if (provider) {\n return { provider, ...parseShorthand(rest) };\n }\n\n // If prefix is not a known provider, treat the whole thing as shorthand\n // This handles cases like owner/repo:path where \"owner/repo\" contains no provider prefix\n return { provider: \"github\", ...parseShorthand(source) };\n }\n\n // Handle shorthand: owner/repo[@ref][:path] - defaults to GitHub\n return { provider: \"github\", ...parseShorthand(source) };\n}\n\n/**\n * Parse URL format into components\n */\nfunction parseUrl(url: string): ParsedSource {\n const urlObj = new URL(url);\n const host = urlObj.hostname.toLowerCase();\n\n let provider: GitProvider;\n if (GITHUB_HOSTS.has(host)) {\n provider = \"github\";\n } else if (GITLAB_HOSTS.has(host)) {\n provider = \"gitlab\";\n } else {\n throw new Error(\n `Unknown Git provider for host: ${host}. Supported providers: ${ALL_GIT_PROVIDERS.join(\", \")}`,\n );\n }\n\n // Split by path segments\n const segments = urlObj.pathname.split(\"/\").filter(Boolean);\n\n if (segments.length < 2) {\n throw new Error(`Invalid ${provider} URL: ${url}. Expected format: https://${host}/owner/repo`);\n }\n\n const owner = segments[0];\n const repo = segments[1]?.replace(/\\.git$/, \"\");\n\n // Check for /tree/ref/path or /blob/ref/path pattern\n if (segments.length > 2 && (segments[2] === \"tree\" || segments[2] === \"blob\")) {\n const ref = segments[3];\n const path = segments.length > 4 ? segments.slice(4).join(\"/\") : undefined;\n return {\n provider,\n owner: owner ?? \"\",\n repo: repo ?? \"\",\n ref,\n path,\n };\n }\n\n return {\n provider,\n owner: owner ?? \"\",\n repo: repo ?? \"\",\n };\n}\n\n/**\n * Parse shorthand format (without provider prefix)\n */\nfunction parseShorthand(source: string): Omit<ParsedSource, \"provider\"> {\n // Pattern: owner/repo[@ref][:path]\n let remaining = source;\n let path: string | undefined;\n let ref: string | undefined;\n\n // Extract path first (after :)\n const colonIndex = remaining.indexOf(\":\");\n if (colonIndex !== -1) {\n path = remaining.substring(colonIndex + 1);\n if (!path) {\n throw new Error(`Invalid source: ${source}. Path cannot be empty after \":\".`);\n }\n remaining = remaining.substring(0, colonIndex);\n }\n\n // Extract ref (after @)\n const atIndex = remaining.indexOf(\"@\");\n if (atIndex !== -1) {\n ref = remaining.substring(atIndex + 1);\n if (!ref) {\n throw new Error(`Invalid source: ${source}. Ref cannot be empty after \"@\".`);\n }\n remaining = remaining.substring(0, atIndex);\n }\n\n // Parse owner/repo\n const slashIndex = remaining.indexOf(\"/\");\n if (slashIndex === -1) {\n throw new Error(\n `Invalid source: ${source}. Expected format: owner/repo, owner/repo@ref, or owner/repo:path`,\n );\n }\n\n const owner = remaining.substring(0, slashIndex);\n const repo = remaining.substring(slashIndex + 1);\n\n if (!owner || !repo) {\n throw new Error(`Invalid source: ${source}. Both owner and repo are required.`);\n }\n\n return {\n owner,\n repo,\n ref,\n path,\n };\n}\n","import { join, posix } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport {\n FETCH_CONCURRENCY_LIMIT,\n MAX_FILE_SIZE,\n RULESYNC_AIIGNORE_FILE_NAME,\n RULESYNC_HOOKS_FILE_NAME,\n RULESYNC_HOOKS_JSONC_FILE_NAME,\n RULESYNC_MCP_FILE_NAME,\n RULESYNC_MCP_JSONC_FILE_NAME,\n RULESYNC_PERMISSIONS_FILE_NAME,\n RULESYNC_PERMISSIONS_JSONC_FILE_NAME,\n RULESYNC_RELATIVE_DIR_PATH,\n} from \"../constants/rulesync-paths.js\";\nimport { ChecksProcessor } from \"../features/checks/checks-processor.js\";\nimport { CommandsProcessor } from \"../features/commands/commands-processor.js\";\nimport { HooksProcessor } from \"../features/hooks/hooks-processor.js\";\nimport { IgnoreProcessor } from \"../features/ignore/ignore-processor.js\";\nimport { McpProcessor } from \"../features/mcp/mcp-processor.js\";\nimport { RulesProcessor } from \"../features/rules/rules-processor.js\";\nimport { SkillsProcessor } from \"../features/skills/skills-processor.js\";\nimport { SubagentsProcessor } from \"../features/subagents/subagents-processor.js\";\nimport type { Feature } from \"../types/features.js\";\nimport { ALL_FEATURES } from \"../types/features.js\";\nimport type { FetchTarget } from \"../types/fetch-targets.js\";\nimport type {\n ConflictStrategy,\n FetchFileResult,\n FetchOptions,\n FetchSummary,\n GitHubFileEntry,\n ParsedSource,\n} from \"../types/fetch.js\";\nimport type { ToolTarget } from \"../types/tool-targets.js\";\nimport {\n checkPathTraversal,\n createTempDirectory,\n fileExists,\n removeTempDirectory,\n toPosixPath,\n writeFileContent,\n} from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { GitHubClient, GitHubClientError } from \"./github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"./github-utils.js\";\nimport { parseSource } from \"./source-parser.js\";\n\n/**\n * Feature to path mapping for filtering (rulesync format)\n */\nconst FEATURE_PATHS: Record<Feature, string[]> = {\n rules: [\"rules\"],\n commands: [\"commands\"],\n subagents: [\"subagents\"],\n skills: [\"skills\"],\n checks: [\"checks\"],\n ignore: [RULESYNC_AIIGNORE_FILE_NAME],\n mcp: [RULESYNC_MCP_FILE_NAME, RULESYNC_MCP_JSONC_FILE_NAME],\n hooks: [RULESYNC_HOOKS_FILE_NAME, RULESYNC_HOOKS_JSONC_FILE_NAME],\n permissions: [RULESYNC_PERMISSIONS_FILE_NAME, RULESYNC_PERMISSIONS_JSONC_FILE_NAME],\n};\n\n/**\n * Check if target is a tool target (not rulesync)\n */\nfunction isToolTarget(target: FetchTarget): target is ToolTarget {\n return target !== \"rulesync\";\n}\n\n/**\n * Validate file size against maximum limit\n * @throws {GitHubClientError} If file size exceeds limit\n */\nfunction validateFileSize(relativePath: string, size: number): void {\n if (size > MAX_FILE_SIZE) {\n throw new GitHubClientError(\n `File \"${relativePath}\" exceeds maximum size limit (${(size / 1024 / 1024).toFixed(2)}MB > ${MAX_FILE_SIZE / 1024 / 1024}MB)`,\n );\n }\n}\n\n/**\n * Result of feature conversion\n */\ntype FeatureConversionResult = {\n converted: number;\n convertedPaths: string[];\n};\n\n/**\n * Processor type for feature conversion\n */\ntype FeatureProcessor = {\n loadToolFiles(): Promise<unknown[]>;\n convertToolFilesToRulesyncFiles(\n toolFiles: unknown[],\n ): Promise<\n Array<{ getRelativeDirPath(): string; getRelativeFilePath(): string; getFileContent(): string }>\n >;\n};\n\n/**\n * Process feature conversion for a single feature type\n * @param processor - The processor to use for loading and converting files\n * @param outputDir - Output directory for converted files\n * @returns The paths of converted files\n */\nasync function processFeatureConversion(params: {\n processor: FeatureProcessor;\n outputDir: string;\n}): Promise<{ paths: string[] }> {\n const { processor, outputDir } = params;\n const paths: string[] = [];\n\n const toolFiles = await processor.loadToolFiles();\n if (toolFiles.length === 0) {\n return { paths: [] };\n }\n\n const rulesyncFiles = await processor.convertToolFilesToRulesyncFiles(toolFiles);\n for (const file of rulesyncFiles) {\n const relativePath = join(file.getRelativeDirPath(), file.getRelativeFilePath());\n const outputPath = join(outputDir, relativePath);\n await writeFileContent(outputPath, file.getFileContent());\n paths.push(relativePath);\n }\n\n return { paths };\n}\n\n/**\n * Convert fetched tool-specific files to rulesync format\n * @param tempDir - Temporary directory containing tool-specific files\n * @param outputDir - Output directory for rulesync files\n * @param target - Tool target to convert from\n * @param features - Features to convert\n * @returns Number of converted files and their paths\n */\nasync function convertFetchedFilesToRulesync(params: {\n tempDir: string;\n outputDir: string;\n target: ToolTarget;\n features: Feature[];\n logger: Logger;\n}): Promise<FeatureConversionResult> {\n const { tempDir, outputDir, target, features, logger } = params;\n const convertedPaths: string[] = [];\n\n // Feature conversion configurations\n // Each config defines how to get supported targets and create a processor\n const featureConfigs: Array<{\n feature: Feature;\n getTargets: () => ToolTarget[];\n createProcessor: () => FeatureProcessor;\n }> = [\n {\n feature: \"rules\",\n getTargets: () => RulesProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new RulesProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"commands\",\n getTargets: () =>\n CommandsProcessor.getToolTargets({ global: false, includeSimulated: false }),\n createProcessor: () =>\n new CommandsProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"subagents\",\n getTargets: () =>\n SubagentsProcessor.getToolTargets({ global: false, includeSimulated: false }),\n createProcessor: () =>\n new SubagentsProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"checks\",\n getTargets: () => ChecksProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new ChecksProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"ignore\",\n getTargets: () => IgnoreProcessor.getToolTargets(),\n createProcessor: () =>\n new IgnoreProcessor({ outputRoot: tempDir, toolTarget: target, logger }),\n },\n {\n feature: \"mcp\",\n getTargets: () => McpProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new McpProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"hooks\",\n getTargets: () => HooksProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new HooksProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n ];\n\n // Process each feature using data-driven approach\n for (const config of featureConfigs) {\n if (!features.includes(config.feature)) {\n continue;\n }\n const supportedTargets = config.getTargets();\n if (!supportedTargets.includes(target)) {\n continue;\n }\n const processor = config.createProcessor();\n const result = await processFeatureConversion({ processor, outputDir });\n convertedPaths.push(...result.paths);\n }\n\n // Skills conversion is not yet supported in fetch command\n // Note: Skills are more complex as they are directory-based.\n // Users can use the import command for skills conversion.\n if (features.includes(\"skills\")) {\n logger.debug(\n \"Skills conversion is not yet supported in fetch command. Use import command instead.\",\n );\n }\n\n return { converted: convertedPaths.length, convertedPaths };\n}\n\n/**\n * Resolve features from options, handling wildcard\n */\nfunction resolveFeatures(features?: string[]): Feature[] {\n if (!features || features.length === 0 || features.includes(\"*\")) {\n return [...ALL_FEATURES];\n }\n return features.filter((f): f is Feature => ALL_FEATURES.includes(f as Feature));\n}\n\n/**\n * Type guard for error objects with statusCode\n */\nfunction hasStatusCode(error: unknown): error is { statusCode: number } {\n if (typeof error !== \"object\" || error === null || !(\"statusCode\" in error)) {\n return false;\n }\n const maybeStatus = Object.getOwnPropertyDescriptor(error, \"statusCode\")?.value;\n return typeof maybeStatus === \"number\";\n}\n\n/**\n * Check if error is a 404 \"not found\" error\n */\nfunction isNotFoundError(error: unknown): boolean {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return true;\n }\n // Also handle plain objects with statusCode property (for test mocks)\n if (hasStatusCode(error) && error.statusCode === 404) {\n return true;\n }\n return false;\n}\n\n/**\n * Parameters for fetch operation\n */\nexport type FetchParams = {\n source: string;\n options?: FetchOptions;\n outputRoot?: string;\n logger: Logger;\n};\n\n/**\n * Fetch files from a Git repository\n * Searches for feature directories (rules/, commands/, skills/, etc.) directly at the specified path\n *\n * When target is \"rulesync\" (default), files are fetched as-is.\n * When target is a tool target (e.g., \"claudecode\"), files are fetched to a temp directory,\n * converted to rulesync format, and written to the output directory.\n */\nexport async function fetchFiles(params: FetchParams): Promise<FetchSummary> {\n const { source, options = {}, outputRoot = process.cwd(), logger } = params;\n\n // Parse source\n const parsed = parseSource(source);\n\n // Check if provider is supported\n if (parsed.provider === \"gitlab\") {\n throw new Error(\n \"GitLab is not yet supported. Currently only GitHub repositories are supported.\",\n );\n }\n\n // Resolve options\n const resolvedRef = options.ref ?? parsed.ref;\n // Normalize backslashes to forward slashes for GitHub API compatibility.\n const resolvedPath = toPosixPath(options.path ?? parsed.path ?? \".\");\n const outputDir = options.output ?? RULESYNC_RELATIVE_DIR_PATH;\n const conflictStrategy: ConflictStrategy = options.conflict ?? \"overwrite\";\n const enabledFeatures = resolveFeatures(options.features);\n const target: FetchTarget = options.target ?? \"rulesync\";\n\n // Validate output directory to prevent path traversal attacks\n checkPathTraversal({\n relativePath: outputDir,\n intendedRootDir: outputRoot,\n });\n\n // Initialize GitHub client\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n\n // Validate repository\n logger.debug(`Validating repository: ${parsed.owner}/${parsed.repo}`);\n const isValid = await client.validateRepository(parsed.owner, parsed.repo);\n if (!isValid) {\n throw new GitHubClientError(\n `Repository not found: ${parsed.owner}/${parsed.repo}. Check the repository name and your access permissions.`,\n 404,\n );\n }\n\n // Resolve ref to use\n const ref = resolvedRef ?? (await client.getDefaultBranch(parsed.owner, parsed.repo));\n logger.debug(`Using ref: ${ref}`);\n\n // If target is a tool format, use conversion flow\n if (isToolTarget(target)) {\n return fetchAndConvertToolFiles({\n client,\n parsed,\n ref,\n resolvedPath,\n enabledFeatures,\n target,\n outputDir,\n outputRoot,\n conflictStrategy,\n logger,\n });\n }\n\n // Create semaphore for concurrency control\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n // Collect all files to fetch from feature directories directly\n const filesToFetch = await collectFeatureFiles({\n client,\n owner: parsed.owner,\n repo: parsed.repo,\n basePath: resolvedPath,\n ref,\n enabledFeatures,\n semaphore,\n logger,\n });\n\n if (filesToFetch.length === 0) {\n logger.warn(`No files found matching enabled features: ${enabledFeatures.join(\", \")}`);\n return {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: [],\n created: 0,\n overwritten: 0,\n skipped: 0,\n };\n }\n\n // Process files in parallel with concurrency control\n const outputBasePath = join(outputRoot, outputDir);\n\n // Validate paths and check file sizes first (synchronous checks)\n for (const { relativePath, size } of filesToFetch) {\n checkPathTraversal({\n relativePath,\n intendedRootDir: outputBasePath,\n });\n\n validateFileSize(relativePath, size);\n }\n\n // Process files in parallel with concurrency control\n // Note: Promise.all fails fast - if any promise rejects, others continue running but\n // may have already written files. This behavior is consistent with sequential execution,\n // but the window for partial writes is larger with parallel execution.\n const results = await Promise.all(\n filesToFetch.map(async ({ remotePath, relativePath }) => {\n const localPath = join(outputBasePath, relativePath);\n const exists = await fileExists(localPath);\n\n if (exists && conflictStrategy === \"skip\") {\n logger.debug(`Skipping existing file: ${relativePath}`);\n return { relativePath, status: \"skipped\" as const };\n }\n\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, remotePath, ref),\n );\n await writeFileContent(localPath, content);\n\n const status = exists ? (\"overwritten\" as const) : (\"created\" as const);\n logger.debug(`Wrote: ${relativePath} (${status})`);\n return { relativePath, status };\n }),\n );\n\n // Calculate summary\n const summary: FetchSummary = {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: results,\n created: results.filter((r) => r.status === \"created\").length,\n overwritten: results.filter((r) => r.status === \"overwritten\").length,\n skipped: results.filter((r) => r.status === \"skipped\").length,\n };\n\n return summary;\n}\n\n/**\n * Collect files from feature directories\n */\nasync function collectFeatureFiles(params: {\n client: GitHubClient;\n owner: string;\n repo: string;\n basePath: string;\n ref: string;\n enabledFeatures: Feature[];\n semaphore: Semaphore;\n logger: Logger;\n}): Promise<Array<{ remotePath: string; relativePath: string; size: number }>> {\n const { client, owner, repo, basePath, ref, enabledFeatures, semaphore, logger } = params;\n\n // Cache directory listing results to avoid duplicate API calls\n // File-based features (ignore, mcp, hooks) all list the same basePath directory\n const dirCache = new Map<string, Promise<GitHubFileEntry[]>>();\n\n async function getCachedDirectory(path: string): Promise<GitHubFileEntry[]> {\n let promise = dirCache.get(path);\n if (promise === undefined) {\n promise = withSemaphore(semaphore, () => client.listDirectory(owner, repo, path, ref));\n dirCache.set(path, promise);\n }\n return promise;\n }\n\n const tasks = enabledFeatures.flatMap((feature) =>\n FEATURE_PATHS[feature].map((featurePath) => ({ feature, featurePath })),\n );\n\n const results = await Promise.all(\n tasks.map(async ({ featurePath }) => {\n const fullPath =\n basePath === \".\" || basePath === \"\" ? featurePath : posix.join(basePath, featurePath);\n const collected: Array<{ remotePath: string; relativePath: string; size: number }> = [];\n\n try {\n // Check if it's a file (mcp.json, .aiignore, hooks.json)\n if (featurePath.includes(\".\")) {\n // Try to get the file directly\n try {\n const entries = await getCachedDirectory(\n basePath === \".\" || basePath === \"\" ? \".\" : basePath,\n );\n const fileEntry = entries.find((e) => e.name === featurePath && e.type === \"file\");\n if (fileEntry) {\n collected.push({\n remotePath: fileEntry.path,\n relativePath: featurePath,\n size: fileEntry.size,\n });\n }\n } catch (error) {\n // Only skip 404 errors (file not found), re-throw other errors\n if (isNotFoundError(error)) {\n logger.debug(`File not found: ${fullPath}`);\n } else {\n throw error;\n }\n }\n } else {\n // It's a directory (rules/, commands/, skills/, subagents/)\n const dirFiles = await listDirectoryRecursive({\n client,\n owner,\n repo,\n path: fullPath,\n ref,\n semaphore,\n });\n\n for (const file of dirFiles) {\n // Calculate relative path from base\n const relativePath =\n basePath === \".\" || basePath === \"\"\n ? file.path\n : file.path.substring(basePath.length + 1);\n\n collected.push({\n remotePath: file.path,\n relativePath,\n size: file.size,\n });\n }\n }\n } catch (error) {\n // Check for 404 errors (feature not found)\n if (isNotFoundError(error)) {\n // Feature directory/file not found, skip silently\n logger.debug(`Feature not found: ${fullPath}`);\n return collected;\n }\n throw error;\n }\n\n return collected;\n }),\n );\n\n return results.flat();\n}\n\n/**\n * Fetch tool-specific files and convert them to rulesync format\n */\nasync function fetchAndConvertToolFiles(params: {\n client: GitHubClient;\n parsed: ParsedSource;\n ref: string;\n resolvedPath: string;\n enabledFeatures: Feature[];\n target: ToolTarget;\n outputDir: string;\n outputRoot: string;\n conflictStrategy: ConflictStrategy;\n logger: Logger;\n}): Promise<FetchSummary> {\n const {\n client,\n parsed,\n ref,\n resolvedPath,\n enabledFeatures,\n target,\n outputDir,\n outputRoot,\n conflictStrategy: _conflictStrategy,\n logger,\n } = params;\n\n // Create a unique temporary directory\n const tempDir = await createTempDirectory();\n logger.debug(`Created temp directory: ${tempDir}`);\n\n // Create semaphore for concurrency control\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n try {\n // Collect files using rulesync feature paths (rules/, commands/, etc.)\n // External repos use these paths directly without tool-specific prefixes\n const filesToFetch = await collectFeatureFiles({\n client,\n owner: parsed.owner,\n repo: parsed.repo,\n basePath: resolvedPath,\n ref,\n enabledFeatures,\n semaphore,\n logger,\n });\n\n if (filesToFetch.length === 0) {\n logger.warn(`No files found matching enabled features: ${enabledFeatures.join(\", \")}`);\n return {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: [],\n created: 0,\n overwritten: 0,\n skipped: 0,\n };\n }\n\n // Validate file sizes first\n for (const { relativePath, size } of filesToFetch) {\n validateFileSize(relativePath, size);\n }\n\n // Fetch files to temp directory with tool-specific structure in parallel\n // Map rulesync paths to tool-specific paths\n const toolPaths = getToolPathMapping(target);\n\n await Promise.all(\n filesToFetch.map(async ({ remotePath, relativePath }) => {\n // Map the relative path to tool-specific structure\n const toolRelativePath = mapToToolPath(relativePath, toolPaths);\n checkPathTraversal({\n relativePath: toolRelativePath,\n intendedRootDir: tempDir,\n });\n const localPath = join(tempDir, toolRelativePath);\n\n // Fetch file content with concurrency control, then write locally\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, remotePath, ref),\n );\n await writeFileContent(localPath, content);\n logger.debug(`Fetched to temp: ${toolRelativePath}`);\n }),\n );\n\n // Convert fetched files to rulesync format\n const outputBasePath = join(outputRoot, outputDir);\n const { converted, convertedPaths } = await convertFetchedFilesToRulesync({\n tempDir,\n outputDir: outputBasePath,\n target,\n features: enabledFeatures,\n logger,\n });\n\n // Build results based on conversion with actual file paths\n const results: FetchFileResult[] = convertedPaths.map((relativePath) => ({\n relativePath,\n status: \"created\" as const,\n }));\n\n logger.debug(`Converted ${converted} files from ${target} format to rulesync format`);\n\n return {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: results,\n created: results.filter((r) => r.status === \"created\").length,\n overwritten: results.filter((r) => r.status === \"overwritten\").length,\n skipped: results.filter((r) => r.status === \"skipped\").length,\n };\n } finally {\n // Clean up temp directory\n await removeTempDirectory(tempDir);\n }\n}\n\n/**\n * Get tool-specific path mapping for a target\n * Returns a mapping from rulesync feature paths to tool-specific paths\n */\nfunction getToolPathMapping(target: ToolTarget): {\n rules?: { root?: string; nonRoot?: string };\n commands?: string;\n subagents?: string;\n skills?: string;\n checks?: string;\n} {\n // Get tool-specific paths from each processor class\n const mapping: {\n rules?: { root?: string; nonRoot?: string };\n commands?: string;\n subagents?: string;\n skills?: string;\n checks?: string;\n } = {};\n\n // Rules paths\n const supportedRulesTargets = RulesProcessor.getToolTargets({ global: false });\n if (supportedRulesTargets.includes(target)) {\n const factory = RulesProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.rules = {\n root: paths.root?.relativeFilePath,\n nonRoot: paths.nonRoot?.relativeDirPath,\n };\n }\n }\n\n // Commands paths\n const supportedCommandsTargets = CommandsProcessor.getToolTargets({\n global: false,\n includeSimulated: false,\n });\n if (supportedCommandsTargets.includes(target)) {\n const factory = CommandsProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.commands = paths.relativeDirPath;\n }\n }\n\n // Subagents paths\n const supportedSubagentsTargets = SubagentsProcessor.getToolTargets({\n global: false,\n includeSimulated: false,\n });\n if (supportedSubagentsTargets.includes(target)) {\n const factory = SubagentsProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.subagents = paths.relativeDirPath;\n }\n }\n\n // Skills paths\n const supportedSkillsTargets = SkillsProcessor.getToolTargets({ global: false });\n if (supportedSkillsTargets.includes(target)) {\n const factory = SkillsProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.skills = paths.relativeDirPath;\n }\n }\n\n // Checks paths\n const supportedChecksTargets = ChecksProcessor.getToolTargets({ global: false });\n if (supportedChecksTargets.includes(target)) {\n const factory = ChecksProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.checks = paths.relativeDirPath;\n }\n }\n\n return mapping;\n}\n\n/**\n * Map a rulesync-style relative path to tool-specific path\n */\nfunction mapToToolPath(\n relativePath: string,\n toolPaths: ReturnType<typeof getToolPathMapping>,\n): string {\n // Check if this is a rules file\n if (relativePath.startsWith(\"rules/\")) {\n const restPath = relativePath.substring(\"rules/\".length);\n if (toolPaths.rules?.nonRoot) {\n return join(toolPaths.rules.nonRoot, restPath);\n }\n }\n\n // Check if this is a root rule file (e.g., CLAUDE.md, AGENTS.md)\n if (toolPaths.rules?.root && relativePath === toolPaths.rules.root) {\n return relativePath;\n }\n\n // Check if this is a commands file\n if (relativePath.startsWith(\"commands/\")) {\n const restPath = relativePath.substring(\"commands/\".length);\n if (toolPaths.commands) {\n return join(toolPaths.commands, restPath);\n }\n }\n\n // Check if this is a subagents file\n if (relativePath.startsWith(\"subagents/\")) {\n const restPath = relativePath.substring(\"subagents/\".length);\n if (toolPaths.subagents) {\n return join(toolPaths.subagents, restPath);\n }\n }\n\n // Check if this is a skills file\n if (relativePath.startsWith(\"skills/\")) {\n const restPath = relativePath.substring(\"skills/\".length);\n if (toolPaths.skills) {\n return join(toolPaths.skills, restPath);\n }\n }\n\n // Check if this is a checks file\n if (relativePath.startsWith(\"checks/\")) {\n const restPath = relativePath.substring(\"checks/\".length);\n if (toolPaths.checks) {\n return join(toolPaths.checks, restPath);\n }\n }\n\n // Default: return as-is\n return relativePath;\n}\n\n/**\n * Format fetch summary for display\n */\nexport function formatFetchSummary(summary: FetchSummary): string {\n const lines: string[] = [];\n\n lines.push(`Fetched from ${summary.source}@${summary.ref}:`);\n\n for (const file of summary.files) {\n const icon = file.status === \"skipped\" ? \"-\" : \"\\u2713\";\n const statusText =\n file.status === \"created\"\n ? \"(created)\"\n : file.status === \"overwritten\"\n ? \"(overwritten)\"\n : \"(skipped - already exists)\";\n lines.push(` ${icon} ${file.relativePath} ${statusText}`);\n }\n\n const parts: string[] = [];\n if (summary.created > 0) parts.push(`${summary.created} created`);\n if (summary.overwritten > 0) parts.push(`${summary.overwritten} overwritten`);\n if (summary.skipped > 0) parts.push(`${summary.skipped} skipped`);\n\n lines.push(\"\");\n const summaryText = parts.length > 0 ? parts.join(\", \") : \"no files\";\n lines.push(`Summary: ${summaryText}`);\n\n return lines.join(\"\\n\");\n}\n","import { fetchFiles, formatFetchSummary } from \"../../lib/fetch.js\";\nimport { GitHubClientError } from \"../../lib/github-client.js\";\nimport type { FetchOptions } from \"../../types/fetch.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\nexport type FetchCommandOptions = FetchOptions & {\n source: string;\n};\n\nexport async function fetchCommand(logger: Logger, options: FetchCommandOptions): Promise<void> {\n const { source, ...fetchOptions } = options;\n\n logger.debug(`Fetching files from ${source}...`);\n\n try {\n const summary = await fetchFiles({\n source,\n options: fetchOptions,\n logger,\n });\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n const createdFiles = summary.files\n .filter((f) => f.status === \"created\")\n .map((f) => f.relativePath);\n const overwrittenFiles = summary.files\n .filter((f) => f.status === \"overwritten\")\n .map((f) => f.relativePath);\n const skippedFiles = summary.files\n .filter((f) => f.status === \"skipped\")\n .map((f) => f.relativePath);\n\n logger.captureData(\"source\", source);\n logger.captureData(\"path\", fetchOptions.path);\n logger.captureData(\"created\", createdFiles);\n logger.captureData(\"overwritten\", overwrittenFiles);\n logger.captureData(\"skipped\", skippedFiles);\n logger.captureData(\"totalFetched\", summary.created + summary.overwritten + summary.skipped);\n }\n\n const output = formatFetchSummary(summary);\n\n logger.success(output);\n\n // Exit with appropriate code\n if (summary.created + summary.overwritten === 0 && summary.skipped === 0) {\n logger.warn(\"No files were fetched.\");\n }\n } catch (error) {\n if (error instanceof GitHubClientError) {\n // Include auth hints in error message for JSON mode\n const authHint =\n error.statusCode === 401 || error.statusCode === 403\n ? \" Tip: Set GITHUB_TOKEN or GH_TOKEN environment variable, or use `GITHUB_TOKEN=$(gh auth token) rulesync fetch ...`\"\n : \"\";\n throw new CLIError(`GitHub API Error: ${error.message}.${authHint}`, ErrorCodes.FETCH_FAILED);\n }\n throw error;\n }\n}\n","import { ConfigResolver, type ConfigResolverResolveParams } from \"../../config/config-resolver.js\";\nimport { checkRulesyncDirExists, generate, type GenerateResult } from \"../../lib/generate.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { calculateTotalCount } from \"../../utils/result.js\";\n\nexport type GenerateOptions = ConfigResolverResolveParams;\n\n/**\n * Log feature generation result with appropriate prefix based on dry run mode.\n */\nfunction logFeatureResult(\n logger: Logger,\n params: {\n count: number;\n paths: string[];\n featureName: string;\n isPreview: boolean;\n modePrefix: string;\n },\n): void {\n const { count, paths, featureName, isPreview, modePrefix } = params;\n if (count > 0) {\n if (isPreview) {\n logger.info(`${modePrefix} Would write ${count} ${featureName}`);\n } else {\n logger.success(`Written ${count} ${featureName}`);\n }\n for (const p of paths) {\n logger.info(` ${p}`);\n }\n }\n}\n\nconst FEATURE_DEBUG_MESSAGES: Record<string, string> = {\n ignore: \"Generating ignore files...\",\n mcp: \"Generating MCP files...\",\n commands: \"Generating command files...\",\n subagents: \"Generating subagent files...\",\n skills: \"Generating skill files...\",\n hooks: \"Generating hooks...\",\n checks: \"Generating check files...\",\n rules: \"Generating rule files...\",\n};\n\n// Order in which per-feature debug messages are emitted; matches the original\n// sequential `if (features.includes(...))` ladder.\nconst FEATURE_DEBUG_ORDER = [\n \"ignore\",\n \"mcp\",\n \"commands\",\n \"subagents\",\n \"skills\",\n \"hooks\",\n \"checks\",\n \"rules\",\n] as const;\n\nfunction logFeatureDebugMessages(logger: Logger, features: readonly string[]): void {\n for (const feature of FEATURE_DEBUG_ORDER) {\n if (features.includes(feature)) {\n logger.debug(FEATURE_DEBUG_MESSAGES[feature] ?? \"\");\n }\n }\n}\n\n/**\n * Build the human-readable per-feature summary fragments (e.g. \"3 rules\") for\n * features that produced at least one file. Order matches the original\n * sequential `if (count > 0) parts.push(...)` ladder.\n */\nfunction buildSummaryParts(result: GenerateResult): string[] {\n const summarySpecs: { count: number; label: string }[] = [\n { count: result.rulesCount, label: \"rules\" },\n { count: result.ignoreCount, label: \"ignore files\" },\n { count: result.mcpCount, label: \"MCP files\" },\n { count: result.commandsCount, label: \"commands\" },\n { count: result.subagentsCount, label: \"subagents\" },\n { count: result.skillsCount, label: \"skills\" },\n { count: result.hooksCount, label: \"hooks\" },\n { count: result.permissionsCount, label: \"permissions\" },\n { count: result.checksCount, label: \"checks\" },\n ];\n\n const parts: string[] = [];\n for (const { count, label } of summarySpecs) {\n if (count > 0) parts.push(`${count} ${label}`);\n }\n return parts;\n}\n\nexport async function generateCommand(logger: Logger, options: GenerateOptions): Promise<void> {\n const config = await ConfigResolver.resolve(options, { logger });\n\n const check = config.getCheck();\n\n const isPreview = config.isPreviewMode();\n const modePrefix = isPreview ? \"[DRY RUN]\" : \"\";\n\n logger.debug(\"Generating files...\");\n\n if (!(await checkRulesyncDirExists({ inputRoot: config.getInputRoot() }))) {\n throw new CLIError(\n \".rulesync directory not found. Run 'rulesync init' first.\",\n ErrorCodes.RULESYNC_DIR_NOT_FOUND,\n );\n }\n\n logger.debug(`Output roots: ${config.getOutputRoots().join(\", \")}`);\n\n const features = config.getFeatures();\n\n logFeatureDebugMessages(logger, features);\n\n const result = await generate({ config, logger });\n\n const totalGenerated = calculateTotalCount(result);\n\n // Log feature results and capture data for JSON mode\n const featureResults = {\n ignore: { count: result.ignoreCount, paths: result.ignorePaths },\n mcp: { count: result.mcpCount, paths: result.mcpPaths },\n commands: { count: result.commandsCount, paths: result.commandsPaths },\n subagents: { count: result.subagentsCount, paths: result.subagentsPaths },\n skills: { count: result.skillsCount, paths: result.skillsPaths },\n hooks: { count: result.hooksCount, paths: result.hooksPaths },\n permissions: { count: result.permissionsCount, paths: result.permissionsPaths },\n checks: { count: result.checksCount, paths: result.checksPaths },\n rules: { count: result.rulesCount, paths: result.rulesPaths },\n };\n\n // Map feature keys to human-readable labels with pluralization\n const featureLabels: Record<string, (count: number) => string> = {\n rules: (count) => `${count === 1 ? \"rule\" : \"rules\"}`,\n ignore: (count) => `${count === 1 ? \"ignore file\" : \"ignore files\"}`,\n mcp: (count) => `${count === 1 ? \"MCP file\" : \"MCP files\"}`,\n commands: (count) => `${count === 1 ? \"command\" : \"commands\"}`,\n subagents: (count) => `${count === 1 ? \"subagent\" : \"subagents\"}`,\n skills: (count) => `${count === 1 ? \"skill\" : \"skills\"}`,\n hooks: (count) => `${count === 1 ? \"hooks file\" : \"hooks files\"}`,\n permissions: (count) => `${count === 1 ? \"permissions file\" : \"permissions files\"}`,\n checks: (count) => `${count === 1 ? \"check\" : \"checks\"}`,\n };\n\n for (const [feature, data] of Object.entries(featureResults)) {\n logFeatureResult(logger, {\n count: data.count,\n paths: data.paths,\n featureName: featureLabels[feature]?.(data.count) ?? feature,\n isPreview,\n modePrefix,\n });\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"features\", featureResults);\n logger.captureData(\"totalFiles\", totalGenerated);\n logger.captureData(\"hasDiff\", result.hasDiff);\n logger.captureData(\"skills\", result.skills ?? []);\n }\n\n // Check mode must fail even when the change is delete-only and no files are written.\n if (check) {\n if (result.hasDiff) {\n throw new CLIError(\n \"Files are not up to date. Run 'rulesync generate' to update.\",\n ErrorCodes.GENERATION_FAILED,\n );\n }\n\n logger.success(\"✓ All files are up to date.\");\n return;\n }\n\n if (totalGenerated === 0) {\n const enabledFeatures = features.join(\", \");\n logger.info(`✓ All files are up to date (${enabledFeatures})`);\n return;\n }\n\n const parts = buildSummaryParts(result);\n\n if (isPreview) {\n logger.info(`${modePrefix} Would write ${totalGenerated} file(s) total (${parts.join(\" + \")})`);\n } else {\n logger.success(`🎉 All done! Written ${totalGenerated} file(s) total (${parts.join(\" + \")})`);\n }\n}\n","import type { ToolRuleExtraFixedFile } from \"../../features/rules/tool-rule.js\";\nimport type { Feature } from \"../../types/features.js\";\nimport { getProcessorRegistryEntry } from \"../../types/processor-registry.js\";\nimport type { ToolTarget } from \"../../types/tool-targets.js\";\n\nexport type GitignoreEntryTarget = ToolTarget | \"common\";\n\nexport type GitignoreEntryTag = {\n readonly target: GitignoreEntryTarget | ReadonlyArray<GitignoreEntryTarget>;\n readonly feature: Feature | \"general\";\n readonly entry: string;\n};\n\n// Targets excluded from derivation: they don't generate project files\n// (agentsskills) or are deprecated aliases whose outputs are covered elsewhere\n// (augmentcode-legacy → augmentcode, claudecode-legacy → claudecode).\nconst TARGETS_NOT_DERIVED: ReadonlySet<string> = new Set([\n \"agentsskills\",\n \"augmentcode-legacy\",\n \"claudecode-legacy\",\n]);\n\n// Project-scope outputs that rulesync merges into rather than fully owns\n// (user-managed settings files), so they are deliberately not gitignored even\n// though a feature emits them. Most paths come straight from a tool's default\n// getSettablePaths; `.amp/settings.jsonc` (runtime probe twin of\n// `.amp/settings.json`) and `.claude/settings.local.json` (claudecode ignore\n// `fileMode: \"local\"` variant) are emitted only under non-default options.\nexport const DERIVED_PATHS_NOT_GITIGNORED: ReadonlySet<string> = new Set([\n \"**/.amp/settings.json\",\n \"**/.amp/settings.jsonc\",\n \"**/.antigravity/settings.json\",\n \"**/.claude/settings.json\",\n \"**/.claude/settings.local.json\",\n \"**/.codex/config.toml\",\n \"**/.devin/config.json\",\n \"**/.factory/settings.json\",\n \"**/.grok/config.toml\",\n \"**/.vibe/config.toml\",\n \"**/reasonix.toml\",\n \"**/.zed/settings.json\",\n \"**/kilo.json\",\n \"**/kilo.jsonc\",\n \"**/opencode.json\",\n]);\n\nconst toPosix = (path: string): string => path.replace(/\\\\/g, \"/\");\n\nconst dirToGlob = (relativeDirPath: string): string =>\n `**/${toPosix(relativeDirPath).replace(/\\/$/, \"\")}/`;\n\nconst fileToGlob = (relativeDirPath: string | undefined, relativeFilePath: string): string => {\n const hasDir = relativeDirPath && relativeDirPath !== \".\";\n return `**/${toPosix(hasDir ? `${relativeDirPath}/${relativeFilePath}` : relativeFilePath)}`;\n};\n\nconst supportsProject = (factory: unknown): boolean => {\n if (typeof factory !== \"object\" || factory === null || !(\"meta\" in factory)) return true;\n const meta = (factory as { meta?: { supportsProject?: boolean } }).meta;\n return meta?.supportsProject !== false;\n};\n\ntype SettablePathsFn = (options?: { global?: boolean }) => unknown;\n\ntype FactoryMap = ReadonlyMap<ToolTarget, { readonly class: { getSettablePaths: unknown } }>;\n\nconst getProjectPaths = (factory: { class: { getSettablePaths: unknown } }): unknown =>\n (factory.class.getSettablePaths as SettablePathsFn)({ global: false });\n\nconst pushEntry = (\n entries: GitignoreEntryTag[],\n target: ToolTarget,\n feature: Feature,\n entry: string,\n): void => {\n entries.push({ target, feature, entry });\n};\n\nconst deriveDirEntries = (factories: FactoryMap, feature: Feature): GitignoreEntryTag[] => {\n const entries: GitignoreEntryTag[] = [];\n for (const [target, factory] of factories) {\n if (TARGETS_NOT_DERIVED.has(target)) continue;\n if (!supportsProject(factory)) continue;\n const paths = getProjectPaths(factory) as { relativeDirPath?: string };\n const dir = paths.relativeDirPath;\n if (!dir || dir === \".\") continue;\n pushEntry(entries, target, feature, dirToGlob(dir));\n }\n return entries;\n};\n\nconst deriveFileEntries = (factories: FactoryMap, feature: Feature): GitignoreEntryTag[] => {\n const entries: GitignoreEntryTag[] = [];\n for (const [target, factory] of factories) {\n if (TARGETS_NOT_DERIVED.has(target)) continue;\n if (!supportsProject(factory)) continue;\n const paths = getProjectPaths(factory) as {\n relativeDirPath?: string;\n relativeFilePath?: string;\n };\n if (!paths.relativeFilePath) continue;\n pushEntry(entries, target, feature, fileToGlob(paths.relativeDirPath, paths.relativeFilePath));\n }\n return entries;\n};\n\n// Rules have a composite shape: root/alternativeRoots are files, nonRoot is a\n// directory subtree.\nconst deriveRulesEntries = (): GitignoreEntryTag[] => {\n const entries: GitignoreEntryTag[] = [];\n const factories = getProcessorRegistryEntry(\"rules\").factory as unknown as FactoryMap;\n for (const [target, factory] of factories) {\n if (TARGETS_NOT_DERIVED.has(target)) continue;\n const paths = getProjectPaths(factory) as {\n root?: { relativeDirPath: string; relativeFilePath: string };\n alternativeRoots?: ReadonlyArray<{ relativeDirPath: string; relativeFilePath: string }>;\n nonRoot?: { relativeDirPath: string } | null;\n };\n for (const root of [paths.root, ...(paths.alternativeRoots ?? [])]) {\n if (root)\n pushEntry(\n entries,\n target,\n \"rules\",\n fileToGlob(root.relativeDirPath, root.relativeFilePath),\n );\n }\n const nonRootDir = paths.nonRoot?.relativeDirPath;\n if (nonRootDir && nonRootDir !== \".\") {\n pushEntry(entries, target, \"rules\", dirToGlob(nonRootDir));\n }\n // Extra fixed-path files a tool manages beyond root/nonRoot (e.g. Pi's\n // `.pi/APPEND_SYSTEM.md`). Derived from the same hook the RulesProcessor uses.\n const classWithExtraFiles = factory.class as {\n getExtraFixedFiles?: (options?: { global?: boolean }) => ToolRuleExtraFixedFile[];\n };\n if (classWithExtraFiles.getExtraFixedFiles) {\n for (const file of classWithExtraFiles.getExtraFixedFiles({ global: false })) {\n pushEntry(\n entries,\n target,\n \"rules\",\n fileToGlob(file.relativeDirPath, file.relativeFilePath),\n );\n }\n }\n }\n return entries;\n};\n\n// commands/skills/subagents/checks emit a directory tree; mcp/hooks/permissions/ignore\n// emit a single file; rules has a composite root+nonRoot shape.\nconst DIR_FEATURES = new Set<Feature>([\"commands\", \"skills\", \"subagents\", \"checks\"]);\nconst FILE_FEATURES = new Set<Feature>([\"mcp\", \"hooks\", \"permissions\", \"ignore\"]);\n\nconst deriveFeatureGitignoreEntries = (feature: Feature): GitignoreEntryTag[] => {\n if (feature === \"rules\") return deriveRulesEntries();\n const factory = getProcessorRegistryEntry(feature).factory as unknown as FactoryMap;\n if (DIR_FEATURES.has(feature)) return deriveDirEntries(factory, feature);\n if (FILE_FEATURES.has(feature)) return deriveFileEntries(factory, feature);\n return [];\n};\n\nconst DERIVED_FEATURES: ReadonlyArray<Feature> = [\n \"rules\",\n \"commands\",\n \"skills\",\n \"subagents\",\n \"mcp\",\n \"hooks\",\n \"permissions\",\n \"ignore\",\n \"checks\",\n];\n\n// Every project-scope output path, derived from each tool's getSettablePaths,\n// BEFORE the DERIVED_PATHS_NOT_GITIGNORED exclusion is applied. Exported so\n// tests can verify each exclusion-set path still matches a real output path.\nexport const deriveAllGitignoreEntriesUnfiltered = (): GitignoreEntryTag[] =>\n DERIVED_FEATURES.flatMap((feature) => deriveFeatureGitignoreEntries(feature));\n\n// Every gitignore entry rulesync emits, derived from each tool's getSettablePaths.\nexport const deriveAllGitignoreEntries = (): GitignoreEntryTag[] =>\n deriveAllGitignoreEntriesUnfiltered().filter(\n (tag) => !DERIVED_PATHS_NOT_GITIGNORED.has(tag.entry),\n );\n","import {\n CLAUDECODE_DIR,\n CLAUDECODE_LOCAL_RULE_FILE_NAME,\n CLAUDECODE_MEMORIES_DIR_NAME,\n CLAUDECODE_SETTINGS_LOCAL_FILE_NAME,\n} from \"../../constants/claudecode-paths.js\";\nimport { CODEXCLI_BASH_RULES_FILE_NAME, CODEXCLI_DIR } from \"../../constants/codexcli-paths.js\";\nimport { RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH } from \"../../constants/rulesync-paths.js\";\nimport {\n ALL_FEATURES_WITH_WILDCARD,\n type Feature,\n type RulesyncFeatures,\n} from \"../../types/features.js\";\nimport { ALL_TOOL_TARGETS_WITH_WILDCARD } from \"../../types/tool-targets.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport {\n deriveAllGitignoreEntries,\n type GitignoreEntryTag,\n type GitignoreEntryTarget,\n} from \"./gitignore-derive.js\";\n\nconst normalizeGitignoreEntryTargets = (\n target: GitignoreEntryTag[\"target\"],\n): ReadonlyArray<GitignoreEntryTarget> => {\n return typeof target === \"string\" ? [target] : target;\n};\n\n// Hand-maintained entries that are NOT derivable from any tool's\n// getSettablePaths, because they are not rulesync-owned generated outputs:\n// - rulesync's own meta files (`.rulesync/**`, `rulesync.local.jsonc`, the\n// `AGENTS.local.md` / `CLAUDE.local.md` local-root files, the `.aiignore`\n// un-ignore exception)\n// - third-party tool by-products rulesync never writes but gitignores as a\n// convenience (`.claude/*.lock`, `.takt/runs/`, lock files, …)\n// - the `.codexignore` ghost (codexcli has no ignore processor)\n// Everything a tool actually emits is derived below from getSettablePaths.\nexport const HAND_MAINTAINED_GITIGNORE_ENTRIES: ReadonlyArray<GitignoreEntryTag> = [\n // rulesync's own meta files (common scope).\n {\n target: \"common\",\n feature: \"general\",\n entry: `${RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH}/`,\n },\n { target: \"common\", feature: \"general\", entry: \".rulesync/rules/*.local.md\" },\n { target: \"common\", feature: \"general\", entry: \"rulesync.local.jsonc\" },\n // AGENTS.local.md is placed in common scope (not rovodev-only) so that\n // local rule files are always gitignored regardless of which targets are enabled.\n { target: \"common\", feature: \"general\", entry: \"**/AGENTS.local.md\" },\n\n // Local-root rule files: materialized outside getSettablePaths.\n { target: \"claudecode\", feature: \"rules\", entry: `**/${CLAUDECODE_LOCAL_RULE_FILE_NAME}` },\n {\n target: \"claudecode\",\n feature: \"rules\",\n entry: `**/${CLAUDECODE_DIR}/${CLAUDECODE_LOCAL_RULE_FILE_NAME}`,\n },\n\n // Third-party tool by-products rulesync gitignores but never writes itself.\n { target: \"claudecode\", feature: \"general\", entry: `**/${CLAUDECODE_DIR}/*.lock` },\n {\n target: \"claudecode\",\n feature: \"general\",\n entry: `**/${CLAUDECODE_DIR}/${CLAUDECODE_SETTINGS_LOCAL_FILE_NAME}`,\n },\n {\n target: \"claudecode\",\n feature: \"general\",\n entry: `**/${CLAUDECODE_DIR}/${CLAUDECODE_MEMORIES_DIR_NAME}/`,\n },\n { target: \"opencode\", feature: \"general\", entry: \"**/.opencode/package-lock.json\" },\n { target: \"rovodev\", feature: \"general\", entry: \"**/.rovodev/.rulesync/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/runs/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/tasks/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/.cache/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/config.yaml\" },\n\n // Augment Code's legacy single-file rules path: accepted on import but never\n // generated (so not in getSettablePaths), gitignored as a convenience.\n { target: \"augmentcode\", feature: \"rules\", entry: \"**/.augment-guidelines\" },\n\n // Devin's legacy Windsurf-era workflows directory: commands are now emitted\n // onto the skills surface, but outputs generated by earlier rulesync versions\n // may still exist there, so keep them gitignored as a convenience.\n { target: \"devin\", feature: \"commands\", entry: \"**/.devin/workflows/\" },\n\n // Junie's undocumented memories directory: non-root rules are now folded\n // into the root `.junie/AGENTS.md`, but outputs generated by earlier\n // rulesync versions may still exist there, so keep them gitignored.\n { target: \"junie\", feature: \"rules\", entry: \"**/.junie/memories/\" },\n\n // Shared trees and global-scope outputs not produced via project getSettablePaths.\n { target: \"rovodev\", feature: \"skills\", entry: \"**/.agents/skills/\" },\n // The `prompts.yml` manifest is produced via `RovodevCommand.getAuxiliaryFiles`,\n // not `getSettablePaths` (only the sibling `.rovodev/prompts/` content-file\n // directory is derived automatically), so it needs a hand-maintained entry.\n { target: \"rovodev\", feature: \"commands\", entry: \"**/.rovodev/prompts.yml\" },\n { target: \"devin\", feature: \"skills\", entry: \"**/.config/devin/skills/\" },\n { target: \"copilotcli\", feature: \"subagents\", entry: \"**/.copilot/agents/\" },\n { target: \"copilotcli\", feature: \"mcp\", entry: \"**/.copilot/mcp-config.json\" },\n { target: \"copilotcli\", feature: \"hooks\", entry: \"**/.copilot/hooks/\" },\n { target: \"deepagents\", feature: \"hooks\", entry: \"**/.deepagents/hooks.json\" },\n\n // Roo aggregates subagents into a single `.roomodes` file (no settable path).\n { target: \"roo\", feature: \"subagents\", entry: \"**/.roomodes\" },\n\n // codexcli has no ignore processor; its `.codexignore` is a ghost entry.\n { target: \"codexcli\", feature: \"ignore\", entry: \"**/.codexignore\" },\n\n // Codex CLI's `rulesync.rules` bash-permission file is produced by\n // `createCodexcliBashRulesFile` in codexcli-permissions.ts. That file is\n // written outside `getSettablePaths`, so it is not derived automatically and\n // needs a hand-maintained entry. Only the single rulesync-owned file is\n // ignored: `.codex/rules/` is a general Codex rules location where users can\n // hand-author their own `*.rules` files that should stay version-controlled.\n {\n target: \"codexcli\",\n feature: \"permissions\",\n entry: `**/${CODEXCLI_DIR}/rules/${CODEXCLI_BASH_RULES_FILE_NAME}`,\n },\n];\n\nexport const GITIGNORE_ENTRY_REGISTRY: ReadonlyArray<GitignoreEntryTag> = [\n ...HAND_MAINTAINED_GITIGNORE_ENTRIES,\n\n // Every entry a tool actually emits, derived from its getSettablePaths.\n ...deriveAllGitignoreEntries(),\n\n // Keep this after ignore entries like Junie's \"**/.aiignore\" so the exception remains effective.\n { target: \"common\", feature: \"general\", entry: \"!.rulesync/.aiignore\" },\n];\n\nexport const ALL_GITIGNORE_ENTRIES: ReadonlyArray<string> = (() => {\n // The registry may register the SAME entry under multiple feature tags\n // The exported list dedupes while preserving the original insertion order.\n const seen = new Set<string>();\n const result: string[] = [];\n for (const tag of GITIGNORE_ENTRY_REGISTRY) {\n if (seen.has(tag.entry)) continue;\n seen.add(tag.entry);\n result.push(tag.entry);\n }\n return result;\n})();\n\ntype FilterGitignoreEntriesParams = {\n readonly targets?: ReadonlyArray<string>;\n readonly features?: RulesyncFeatures;\n};\n\nexport type ResolvedGitignoreEntry = {\n readonly entry: string;\n readonly target: ReadonlyArray<GitignoreEntryTarget>;\n readonly feature: Feature | \"general\";\n};\n\nconst isTargetSelected = (\n target: GitignoreEntryTag[\"target\"],\n selectedTargets: ReadonlyArray<string> | undefined,\n): boolean => {\n const targets = normalizeGitignoreEntryTargets(target);\n\n if (targets.includes(\"common\")) return true;\n if (!selectedTargets || selectedTargets.length === 0) return true;\n if (selectedTargets.includes(\"*\")) return true;\n return targets.some((candidate) => selectedTargets.includes(candidate));\n};\n\nconst getSelectedGitignoreEntryTargets = (\n target: GitignoreEntryTag[\"target\"],\n selectedTargets: ReadonlyArray<string> | undefined,\n): ReadonlyArray<GitignoreEntryTarget> => {\n const targets = normalizeGitignoreEntryTargets(target);\n\n if (targets.includes(\"common\")) return [\"common\"];\n if (!selectedTargets || selectedTargets.length === 0 || selectedTargets.includes(\"*\")) {\n return targets;\n }\n\n return targets.filter((candidate) => selectedTargets.includes(candidate));\n};\n\nconst isFeatureSelected = (\n feature: Feature | \"general\",\n features: RulesyncFeatures | undefined,\n): boolean => {\n if (feature === \"general\") return true;\n if (!features) return true;\n if (features.length === 0) return true;\n if (features.includes(\"*\")) return true;\n return features.includes(feature);\n};\n\nconst warnInvalidTargets = (targets: ReadonlyArray<string>, logger?: Logger): void => {\n const validTargets = new Set<string>(ALL_TOOL_TARGETS_WITH_WILDCARD);\n for (const target of targets) {\n if (!validTargets.has(target)) {\n logger?.warn(\n `Unknown target '${target}'. Valid targets: ${ALL_TOOL_TARGETS_WITH_WILDCARD.join(\", \")}`,\n );\n }\n }\n};\n\nconst warnInvalidFeatures = (features: RulesyncFeatures, logger?: Logger): void => {\n const validFeatures = new Set<string>(ALL_FEATURES_WITH_WILDCARD);\n const warned = new Set<string>();\n for (const feature of features) {\n if (!validFeatures.has(feature) && !warned.has(feature)) {\n warned.add(feature);\n logger?.warn(\n `Unknown feature '${feature}'. Valid features: ${ALL_FEATURES_WITH_WILDCARD.join(\", \")}`,\n );\n }\n }\n};\n\nexport const filterGitignoreEntries = (\n params?: FilterGitignoreEntriesParams & { logger?: Logger },\n): string[] => {\n return resolveGitignoreEntries(params).map((entry) => entry.entry);\n};\n\nexport const resolveGitignoreEntries = (\n params?: FilterGitignoreEntriesParams & { logger?: Logger },\n): ResolvedGitignoreEntry[] => {\n const { targets, features, logger } = params ?? {};\n\n if (targets && targets.length > 0) {\n warnInvalidTargets(targets, logger);\n }\n if (features) {\n warnInvalidFeatures(features, logger);\n }\n\n const seen = new Set<string>();\n const result: ResolvedGitignoreEntry[] = [];\n\n for (const tag of GITIGNORE_ENTRY_REGISTRY) {\n if (!isTargetSelected(tag.target, targets)) continue;\n const selectedTagTargets = getSelectedGitignoreEntryTargets(tag.target, targets);\n if (!isFeatureSelected(tag.feature, features)) continue;\n if (seen.has(tag.entry)) continue;\n seen.add(tag.entry);\n result.push({\n entry: tag.entry,\n target: selectedTagTargets,\n feature: tag.feature,\n });\n }\n\n return result;\n};\n","import { join } from \"node:path\";\n\nimport { ConfigResolver } from \"../../config/config-resolver.js\";\nimport type { Feature, GitignoreDestination, RulesyncFeatures } from \"../../types/features.js\";\nimport type { ToolTarget } from \"../../types/tool-targets.js\";\nimport { fileExists, readFileContent, writeFileContent } from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport {\n ALL_GITIGNORE_ENTRIES,\n resolveGitignoreEntries,\n type ResolvedGitignoreEntry,\n} from \"./gitignore-entries.js\";\n\n// Start / end markers that delimit the auto-generated block. Wrapping the\n// managed entries with an explicit footer lets `removeExistingRulesyncEntries`\n// strip the block deterministically instead of guessing where it ends.\nconst RULESYNC_HEADER = \"# Generated by Rulesync\";\nconst RULESYNC_FOOTER = \"# End of Rulesync\";\nconst LEGACY_RULESYNC_HEADER = \"# Generated by rulesync - AI tool configuration files\";\n\nconst isRulesyncHeader = (line: string): boolean => {\n const trimmed = line.trim();\n return trimmed === RULESYNC_HEADER || trimmed === LEGACY_RULESYNC_HEADER;\n};\n\nconst isRulesyncFooter = (line: string): boolean => {\n return line.trim() === RULESYNC_FOOTER;\n};\n\nconst isRulesyncEntry = (line: string): boolean => {\n const trimmed = line.trim();\n if (trimmed === \"\" || isRulesyncHeader(line) || isRulesyncFooter(line)) {\n return false;\n }\n return ALL_GITIGNORE_ENTRIES.includes(trimmed);\n};\n\n// Locate the footer that closes the block opened at `start - 1`. Returns -1 when\n// no footer appears before the next header (i.e. a legacy, marker-less block).\nconst findRulesyncFooterIndex = (lines: string[], start: number): number => {\n for (let index = start; index < lines.length; index++) {\n const line = lines[index] ?? \"\";\n if (isRulesyncFooter(line)) {\n return index;\n }\n if (isRulesyncHeader(line)) {\n return -1;\n }\n }\n return -1;\n};\n\n// Legacy fallback for blocks written before the footer marker existed: skip the\n// header and its following rulesync entries, stopping at two consecutive blank\n// lines or the first line that is neither blank nor a known rulesync entry.\nconst skipLegacyRulesyncBlock = (lines: string[], headerIndex: number): number => {\n let index = headerIndex + 1;\n let consecutiveEmptyLines = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n\n if (line.trim() === \"\") {\n consecutiveEmptyLines++;\n index++;\n if (consecutiveEmptyLines >= 2) {\n break;\n }\n continue;\n }\n\n if (isRulesyncEntry(line)) {\n consecutiveEmptyLines = 0;\n index++;\n continue;\n }\n\n // A non-blank, non-entry line ends the legacy block; leave it untouched.\n break;\n }\n\n return index;\n};\n\nconst removeExistingRulesyncEntries = (content: string): string => {\n const lines = content.split(\"\\n\");\n const filteredLines: string[] = [];\n let index = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n\n if (isRulesyncHeader(line)) {\n const footerIndex = findRulesyncFooterIndex(lines, index + 1);\n if (footerIndex !== -1) {\n // Marker-delimited block: drop everything from header to footer.\n index = footerIndex + 1;\n continue;\n }\n // No footer found: this is a legacy block, remove it heuristically.\n index = skipLegacyRulesyncBlock(lines, index);\n continue;\n }\n\n // Stray rulesync entries left outside a block (e.g. legacy leftovers).\n if (isRulesyncEntry(line)) {\n index++;\n continue;\n }\n\n filteredLines.push(line);\n index++;\n }\n\n let result = filteredLines.join(\"\\n\");\n\n while (result.endsWith(\"\\n\\n\")) {\n result = result.slice(0, -1);\n }\n\n return result;\n};\n\n// Collect the entries currently sitting inside rulesync-managed blocks (plus\n// stray recognized entries outside them), so the command can report which\n// previously managed paths are about to stop being gitignored.\nconst extractRulesyncManagedEntries = (content: string): string[] => {\n const lines = content.split(\"\\n\");\n const managed: string[] = [];\n let index = 0;\n\n const collectBlockLines = (start: number, end: number): void => {\n for (const blockLine of lines.slice(start, end)) {\n const trimmed = blockLine.trim();\n if (trimmed !== \"\") {\n managed.push(trimmed);\n }\n }\n };\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n\n if (isRulesyncHeader(line)) {\n const footerIndex = findRulesyncFooterIndex(lines, index + 1);\n if (footerIndex !== -1) {\n collectBlockLines(index + 1, footerIndex);\n index = footerIndex + 1;\n continue;\n }\n const legacyEnd = skipLegacyRulesyncBlock(lines, index);\n collectBlockLines(index + 1, legacyEnd);\n index = legacyEnd;\n continue;\n }\n\n if (isRulesyncEntry(line)) {\n managed.push(line.trim());\n }\n index++;\n }\n\n return managed;\n};\n\nexport type GitignoreCommandOptions = {\n readonly targets?: string[];\n readonly features?: RulesyncFeatures;\n};\n\nconst groupEntriesByDestination = ({\n entries,\n resolveDestination,\n}: {\n entries: ReadonlyArray<ResolvedGitignoreEntry>;\n resolveDestination: (target: ToolTarget, feature?: Feature | \"general\") => GitignoreDestination;\n}): { gitignore: string[]; gitattributes: string[] } => {\n const gitignore = new Set<string>();\n const gitattributes = new Set<string>();\n\n for (const entry of entries) {\n const selectedToolTargets = entry.target.filter(\n (target): target is ToolTarget => target !== \"common\",\n );\n const destinations = new Set<GitignoreDestination>();\n for (const target of selectedToolTargets) {\n if (entry.feature === \"general\") {\n destinations.add(resolveDestination(target));\n } else {\n destinations.add(resolveDestination(target, entry.feature));\n }\n }\n\n if (destinations.has(\"gitattributes\")) {\n gitattributes.add(entry.entry);\n }\n if (destinations.size === 0 || destinations.has(\"gitignore\")) {\n gitignore.add(entry.entry);\n }\n }\n\n return {\n gitignore: [...gitignore],\n gitattributes: [...gitattributes],\n };\n};\n\nexport const gitignoreCommand = async (\n logger: Logger,\n options?: GitignoreCommandOptions,\n): Promise<void> => {\n const gitignorePath = join(process.cwd(), \".gitignore\");\n const gitattributesPath = join(process.cwd(), \".gitattributes\");\n const config = await ConfigResolver.resolve({});\n\n const resolvedEntries = resolveGitignoreEntries({\n targets: options?.targets,\n features: options?.features,\n logger,\n });\n const { gitignore: gitignoreEntries, gitattributes: gitattributesEntries } =\n groupEntriesByDestination({\n entries: resolvedEntries,\n resolveDestination: (target, feature) => {\n if (feature === undefined || feature === \"general\") {\n return config.getGitignoreDestination(target);\n }\n return config.getGitignoreDestination(target, feature);\n },\n });\n\n const updateRulesyncFile = async ({\n filePath,\n entries,\n }: {\n filePath: string;\n entries: string[];\n }): Promise<{\n updated: boolean;\n alreadyExistedEntries: string[];\n entriesToAdd: string[];\n entriesRemoved: string[];\n }> => {\n let content = \"\";\n if (await fileExists(filePath)) {\n content = await readFileContent(filePath);\n }\n const cleanedContent = removeExistingRulesyncEntries(content);\n const entrySet = new Set(entries);\n const entriesRemoved = [\n ...new Set(extractRulesyncManagedEntries(content).filter((entry) => !entrySet.has(entry))),\n ];\n\n const existingEntries = new Set(\n content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && !isRulesyncHeader(line) && !isRulesyncFooter(line)),\n );\n const alreadyExistedEntries = entries.filter((entry) => existingEntries.has(entry));\n const entriesToAdd = entries.filter((entry) => !existingEntries.has(entry));\n const rulesyncBlock = [RULESYNC_HEADER, ...entries, RULESYNC_FOOTER].join(\"\\n\");\n const newContent =\n entries.length === 0\n ? cleanedContent.trim()\n ? `${cleanedContent.trimEnd()}\\n`\n : \"\"\n : cleanedContent.trim()\n ? `${cleanedContent.trimEnd()}\\n\\n${rulesyncBlock}\\n`\n : `${rulesyncBlock}\\n`;\n\n if (content === newContent) {\n return { updated: false, alreadyExistedEntries, entriesToAdd: [], entriesRemoved: [] };\n }\n await writeFileContent(filePath, newContent);\n return { updated: true, alreadyExistedEntries, entriesToAdd, entriesRemoved };\n };\n\n const gitignoreResult = await updateRulesyncFile({\n filePath: gitignorePath,\n entries: gitignoreEntries,\n });\n const gitattributesResult = await updateRulesyncFile({\n filePath: gitattributesPath,\n entries: gitattributesEntries,\n });\n\n if (!gitignoreResult.updated && !gitattributesResult.updated) {\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"entriesAdded\", []);\n logger.captureData(\"gitignorePath\", gitignorePath);\n logger.captureData(\"gitattributesPath\", gitattributesPath);\n logger.captureData(\"alreadyExisted\", [...gitignoreEntries, ...gitattributesEntries]);\n }\n logger.success(\".gitignore / .gitattributes are already up to date\");\n return;\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"entriesAdded\", [\n ...gitignoreResult.entriesToAdd,\n ...gitattributesResult.entriesToAdd,\n ]);\n logger.captureData(\"gitignorePath\", gitignorePath);\n logger.captureData(\"gitattributesPath\", gitattributesPath);\n logger.captureData(\"alreadyExisted\", [\n ...gitignoreResult.alreadyExistedEntries,\n ...gitattributesResult.alreadyExistedEntries,\n ]);\n logger.captureData(\"entriesRemoved\", gitignoreResult.entriesRemoved);\n }\n\n if (gitignoreResult.entriesRemoved.length > 0) {\n logger.warn(\n \"The following entries were removed from the rulesync-managed block in .gitignore and are no longer gitignored by rulesync:\",\n );\n for (const entry of gitignoreResult.entriesRemoved) {\n logger.warn(` ${entry}`);\n }\n logger.warn(\n \"Review these paths before committing — user-managed settings files may contain secrets.\",\n );\n }\n\n if (gitignoreResult.updated) {\n logger.success(\"Updated .gitignore with rulesync entries:\");\n } else {\n logger.success(\".gitignore is already up to date\");\n }\n for (const entry of gitignoreEntries) {\n logger.info(` ${entry}`);\n }\n if (gitattributesEntries.length > 0) {\n if (gitattributesResult.updated) {\n logger.success(\"Updated .gitattributes with rulesync entries:\");\n } else {\n logger.success(\".gitattributes is already up to date\");\n }\n for (const entry of gitattributesEntries) {\n logger.info(` ${entry}`);\n }\n }\n\n logger.info(\"\");\n logger.info(\n \"💡 If you're using Google Antigravity, note that rules, workflows, and skills won't load if they're gitignored.\",\n );\n logger.info(\" You can add the following to .git/info/exclude instead:\");\n logger.info(\" **/.agents/rules/\");\n logger.info(\" **/.agents/workflows/\");\n logger.info(\" **/.agents/skills/\");\n logger.info(\" For more details: https://github.com/dyoshikawa/rulesync/issues/981\");\n};\n","import { ConfigResolver, ConfigResolverResolveParams } from \"../../config/config-resolver.js\";\nimport { importFromTool } from \"../../lib/import.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { calculateTotalCount } from \"../../utils/result.js\";\n\n// `inputRoot` is intentionally excluded: it only affects where source rules\n// are *read from* during `generate`, and `import` does not consume them. Keeping\n// it in the option type would be misleading. Note that this avoids surfacing\n// the \"Ignoring `global: true`\" warning on direct programmatic / CLI callers;\n// users with an `inputRoot` set in their config file (e.g. `rulesync.jsonc`) may\n// still see the warning because `ConfigResolver.resolve` reads `configByFile`\n// regardless of this `Omit`. That residual warning is actionable — it tells\n// the user their config-file `inputRoot` is being ignored during `import`.\nexport type ImportOptions = Omit<\n ConfigResolverResolveParams,\n \"delete\" | \"outputRoots\" | \"inputRoot\"\n>;\n\nexport async function importCommand(logger: Logger, options: ImportOptions): Promise<void> {\n if (!options.targets) {\n throw new CLIError(\"No tools found in --targets\", ErrorCodes.IMPORT_FAILED);\n }\n\n // The CLI only provides the array form for --targets; the object form is\n // config-file-only. Defend with a runtime check so TS can narrow safely.\n if (!Array.isArray(options.targets)) {\n throw new CLIError(\n \"--targets object form is not supported on the command line\",\n ErrorCodes.IMPORT_FAILED,\n );\n }\n\n if (options.targets.length > 1) {\n throw new CLIError(\"Only one tool can be imported at a time\", ErrorCodes.IMPORT_FAILED);\n }\n\n const config = await ConfigResolver.resolve(options, { logger });\n\n const tool = config.getTargets()[0]!;\n\n logger.debug(`Importing files from ${tool}...`);\n\n const result = await importFromTool({ config, tool, logger });\n\n const totalImported = calculateTotalCount(result);\n\n if (totalImported === 0) {\n const enabledFeatures = config.getFeatures().join(\", \");\n logger.warn(`No files imported for enabled features: ${enabledFeatures}`);\n return;\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"tool\", tool);\n logger.captureData(\"features\", {\n rules: { count: result.rulesCount },\n ignore: { count: result.ignoreCount },\n mcp: { count: result.mcpCount },\n commands: { count: result.commandsCount },\n subagents: { count: result.subagentsCount },\n skills: { count: result.skillsCount },\n hooks: { count: result.hooksCount },\n permissions: { count: result.permissionsCount },\n checks: { count: result.checksCount },\n });\n logger.captureData(\"totalFiles\", totalImported);\n }\n\n const parts = [];\n if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);\n if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);\n if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);\n if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);\n if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);\n if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);\n if (result.hooksCount > 0) parts.push(`${result.hooksCount} hooks`);\n if (result.permissionsCount > 0) parts.push(`${result.permissionsCount} permissions`);\n if (result.checksCount > 0) parts.push(`${result.checksCount} checks`);\n\n logger.success(`Imported ${totalImported} file(s) total (${parts.join(\" + \")})`);\n}\n","import { join } from \"node:path\";\n\nimport { ConfigFile } from \"../config/config.js\";\nimport { SKILL_FILE_NAME } from \"../constants/general.js\";\nimport {\n RULESYNC_CONFIG_RELATIVE_FILE_PATH,\n RULESYNC_CONFIG_SCHEMA_URL,\n RULESYNC_MCP_SCHEMA_URL,\n RULESYNC_OVERVIEW_FILE_NAME,\n RULESYNC_PERMISSIONS_SCHEMA_URL,\n} from \"../constants/rulesync-paths.js\";\nimport { RulesyncCommand } from \"../features/commands/rulesync-command.js\";\nimport { RulesyncHooks } from \"../features/hooks/rulesync-hooks.js\";\nimport { RulesyncIgnore } from \"../features/ignore/rulesync-ignore.js\";\nimport { RulesyncMcp } from \"../features/mcp/rulesync-mcp.js\";\nimport { RulesyncPermissions } from \"../features/permissions/rulesync-permissions.js\";\nimport { RulesyncRule } from \"../features/rules/rulesync-rule.js\";\nimport { RulesyncSkill } from \"../features/skills/rulesync-skill.js\";\nimport { RulesyncSubagent } from \"../features/subagents/rulesync-subagent.js\";\nimport { ensureDir, fileExists, writeFileContent } from \"../utils/file.js\";\n\ntype InitFileResult = {\n created: boolean;\n path: string;\n};\n\nexport type InitResult = {\n configFile: InitFileResult;\n sampleFiles: InitFileResult[];\n};\n\n/**\n * Initialize rulesync configuration and sample files.\n * This is the core logic without CLI-specific logging.\n */\nexport async function init(): Promise<InitResult> {\n const sampleFiles = await createSampleFiles();\n const configFile = await createConfigFile();\n\n return {\n configFile,\n sampleFiles,\n };\n}\n\nasync function createConfigFile(): Promise<InitFileResult> {\n const path = RULESYNC_CONFIG_RELATIVE_FILE_PATH;\n\n if (await fileExists(path)) {\n return { created: false, path };\n }\n\n await writeFileContent(\n path,\n JSON.stringify(\n {\n $schema: RULESYNC_CONFIG_SCHEMA_URL,\n targets: [\"copilot\", \"cursor\", \"claudecode\", \"codexcli\"],\n features: [\n \"rules\",\n \"ignore\",\n \"mcp\",\n \"commands\",\n \"subagents\",\n \"skills\",\n \"hooks\",\n \"permissions\",\n ],\n outputRoots: [\".\"],\n delete: true,\n verbose: false,\n silent: false,\n global: false,\n simulateCommands: false,\n simulateSubagents: false,\n simulateSkills: false,\n gitignoreTargetsOnly: true,\n } satisfies ConfigFile,\n null,\n 2,\n ),\n );\n\n return { created: true, path };\n}\n\nasync function createSampleFiles(): Promise<InitFileResult[]> {\n const results: InitFileResult[] = [];\n\n // Sample file contents\n const sampleRuleFile = {\n filename: RULESYNC_OVERVIEW_FILE_NAME,\n content: `---\nroot: true\ntargets: [\"*\"]\ndescription: \"Project overview and general development guidelines\"\nglobs: [\"**/*\"]\n---\n\n# Project Overview\n\n## General Guidelines\n\n- Use TypeScript for all new code\n- Follow consistent naming conventions\n- Write self-documenting code with clear variable and function names\n- Prefer composition over inheritance\n- Use meaningful comments for complex business logic\n\n## Code Style\n\n- Use 2 spaces for indentation\n- Use semicolons\n- Use double quotes for strings\n- Use trailing commas in multi-line objects and arrays\n\n## Architecture Principles\n\n- Organize code by feature, not by file type\n- Keep related files close together\n- Use dependency injection for better testability\n- Implement proper error handling\n- Follow single responsibility principle\n`,\n };\n\n const sampleMcpFile = {\n filename: \"mcp.json\",\n content: `{\n \"$schema\": \"${RULESYNC_MCP_SCHEMA_URL}\",\n \"mcpServers\": {\n \"deepwiki\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.deepwiki.com/mcp\",\n \"env\": {}\n },\n \"rulesync\": {\n \"type\": \"stdio\",\n \"command\": \"pnpm\",\n \"args\": [\n \"dlx\",\n \"rulesync\",\n \"mcp\"\n ],\n \"env\": {}\n }\n }\n}\n`,\n };\n\n const sampleCommandFile = {\n filename: \"review-pr.md\",\n content: `---\ndescription: 'Review a pull request'\ntargets: [\"*\"]\n---\n\ntarget_pr = $ARGUMENTS\n\nIf target_pr is not provided, use the PR of the current branch.\n\nExecute the following in parallel:\n\n1. Check code quality and style consistency\n2. Review test coverage\n3. Verify documentation updates\n4. Check for potential bugs or security issues\n\nThen provide a summary of findings and suggestions for improvement.\n`,\n };\n\n const sampleSubagentFile = {\n filename: \"planner.md\",\n content: `---\nname: planner\ntargets: [\"*\"]\ndescription: >-\n This is the general-purpose planner. The user asks the agent to plan to\n suggest a specification, implement a new feature, refactor the codebase, or\n fix a bug. This agent can be called by the user explicitly only.\nclaudecode:\n model: inherit\n---\n\nYou are the planner for any tasks.\n\nBased on the user's instruction, create a plan while analyzing the related files. Then, report the plan in detail. You can output files to @tmp/ if needed.\n\nAttention, again, you are just the planner, so though you can read any files and run any commands for analysis, please don't write any code.\n`,\n };\n\n const sampleSkillFile = {\n dirName: \"project-context\",\n content: `---\nname: project-context\ndescription: \"Summarize the project context and key constraints\"\ntargets: [\"*\"]\n---\n\nSummarize the project goals, core constraints, and relevant dependencies.\nCall out any architecture decisions, shared conventions, and validation steps.\nKeep the summary concise and ready to reuse in future tasks.`,\n };\n\n const sampleIgnoreFile = {\n content: `credentials/\n`,\n };\n\n const sampleHooksFile = {\n content: `{\n \"version\": 1,\n \"hooks\": {\n \"postToolUse\": [\n {\n \"matcher\": \"Write|Edit\",\n \"command\": \".rulesync/hooks/format.sh\"\n }\n ]\n }\n}\n`,\n };\n\n // Keep the scaffolded defaults conservative: broad \"allow\" globs such as\n // \"git *\" or \"npm run *\" are effectively arbitrary code execution (git can run\n // commands via -c/aliases/hooks; npm run executes package.json scripts), so the\n // sample allows only a few explicit read-only commands and leaves everything\n // else to the \"*\": \"ask\" catch-all. Users can widen it as they see fit.\n const samplePermissionsFile = {\n content: `{\n \"$schema\": \"${RULESYNC_PERMISSIONS_SCHEMA_URL}\",\n \"permission\": {\n \"bash\": {\n \"git status\": \"allow\",\n \"git diff\": \"allow\",\n \"ls *\": \"allow\",\n \"rm -rf *\": \"deny\",\n \"*\": \"ask\"\n },\n \"edit\": {\n \"src/**\": \"allow\"\n },\n \"read\": {\n \".env\": \"deny\"\n }\n }\n}\n`,\n };\n\n // Get paths from settable paths\n const rulePaths = RulesyncRule.getSettablePaths();\n const mcpPaths = RulesyncMcp.getSettablePaths();\n const commandPaths = RulesyncCommand.getSettablePaths();\n const subagentPaths = RulesyncSubagent.getSettablePaths();\n const skillPaths = RulesyncSkill.getSettablePaths();\n const ignorePaths = RulesyncIgnore.getSettablePaths();\n const hooksPaths = RulesyncHooks.getSettablePaths();\n const permissionsPaths = RulesyncPermissions.getSettablePaths();\n\n // Ensure directories\n await ensureDir(rulePaths.recommended.relativeDirPath);\n await ensureDir(mcpPaths.recommended.relativeDirPath);\n await ensureDir(commandPaths.relativeDirPath);\n await ensureDir(subagentPaths.relativeDirPath);\n await ensureDir(skillPaths.relativeDirPath);\n await ensureDir(ignorePaths.recommended.relativeDirPath);\n\n // Create rule sample file\n const ruleFilepath = join(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);\n results.push(await writeIfNotExists(ruleFilepath, sampleRuleFile.content));\n\n // Create MCP sample file\n const mcpFilepath = join(\n mcpPaths.recommended.relativeDirPath,\n mcpPaths.recommended.relativeFilePath,\n );\n results.push(await writeIfNotExists(mcpFilepath, sampleMcpFile.content));\n\n // Create command sample file\n const commandFilepath = join(commandPaths.relativeDirPath, sampleCommandFile.filename);\n results.push(await writeIfNotExists(commandFilepath, sampleCommandFile.content));\n\n // Create subagent sample file\n const subagentFilepath = join(subagentPaths.relativeDirPath, sampleSubagentFile.filename);\n results.push(await writeIfNotExists(subagentFilepath, sampleSubagentFile.content));\n\n // Create skill sample file\n const skillDirPath = join(skillPaths.relativeDirPath, sampleSkillFile.dirName);\n await ensureDir(skillDirPath);\n const skillFilepath = join(skillDirPath, SKILL_FILE_NAME);\n results.push(await writeIfNotExists(skillFilepath, sampleSkillFile.content));\n\n // Create ignore sample file\n const ignoreFilepath = join(\n ignorePaths.recommended.relativeDirPath,\n ignorePaths.recommended.relativeFilePath,\n );\n results.push(await writeIfNotExists(ignoreFilepath, sampleIgnoreFile.content));\n\n // Create hooks sample file\n const hooksFilepath = join(hooksPaths.relativeDirPath, hooksPaths.relativeFilePath);\n results.push(await writeIfNotExists(hooksFilepath, sampleHooksFile.content));\n\n // Create permissions sample file\n const permissionsFilepath = join(\n permissionsPaths.relativeDirPath,\n permissionsPaths.relativeFilePath,\n );\n results.push(await writeIfNotExists(permissionsFilepath, samplePermissionsFile.content));\n\n return results;\n}\n\nasync function writeIfNotExists(path: string, content: string): Promise<InitFileResult> {\n if (await fileExists(path)) {\n return { created: false, path };\n }\n\n await writeFileContent(path, content);\n return { created: true, path };\n}\n","import { SKILL_FILE_NAME } from \"../../constants/general.js\";\nimport {\n RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n RULESYNC_HOOKS_RELATIVE_FILE_PATH,\n RULESYNC_MCP_RELATIVE_FILE_PATH,\n RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH,\n RULESYNC_RELATIVE_DIR_PATH,\n} from \"../../constants/rulesync-paths.js\";\nimport { init } from \"../../lib/init.js\";\nimport { ensureDir } from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\nexport async function initCommand(logger: Logger): Promise<void> {\n logger.debug(\"Initializing rulesync...\");\n\n await ensureDir(RULESYNC_RELATIVE_DIR_PATH);\n\n const result = await init();\n\n // Log sample file results\n const createdFiles: string[] = [];\n const skippedFiles: string[] = [];\n\n for (const file of result.sampleFiles) {\n if (file.created) {\n createdFiles.push(file.path);\n logger.success(`Created ${file.path}`);\n } else {\n skippedFiles.push(file.path);\n logger.info(`Skipped ${file.path} (already exists)`);\n }\n }\n\n // Log config file result\n if (result.configFile.created) {\n createdFiles.push(result.configFile.path);\n logger.success(`Created ${result.configFile.path}`);\n } else {\n skippedFiles.push(result.configFile.path);\n logger.info(`Skipped ${result.configFile.path} (already exists)`);\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"created\", createdFiles);\n logger.captureData(\"skipped\", skippedFiles);\n }\n\n logger.success(\"rulesync initialized successfully!\");\n logger.info(\"Next steps:\");\n logger.info(\n `1. Edit ${RULESYNC_RELATIVE_DIR_PATH}/**/*.md, ${RULESYNC_RELATIVE_DIR_PATH}/skills/*/${SKILL_FILE_NAME}, ${RULESYNC_MCP_RELATIVE_FILE_PATH}, ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}, ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} and ${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}`,\n );\n logger.info(\"2. Run 'rulesync generate' to create configuration files\");\n}\n","import { join } from \"node:path\";\n\nimport { dump } from \"js-yaml\";\nimport { nonnegative, optional, refine, z } from \"zod/mini\";\n\nimport { fileExists, readFileContent, writeFileContent } from \"../../utils/file.js\";\nimport { loadYaml } from \"../../utils/yaml.js\";\n\n/**\n * Filename of the rulesync-managed apm-compatible lockfile. Rulesync uses a\n * lockfile name distinct from the upstream `apm` CLI's `apm.lock.yaml` so the\n * two tools do not fight over the same file: the schema is still the apm v1\n * lockfile format, but rulesync only reads/writes its own file.\n */\nconst APM_LOCKFILE_FILE_NAME = \"rulesync-apm.lock.yaml\";\nexport const APM_LOCKFILE_VERSION = \"1\" as const;\n\n/**\n * Shape of content_hash values that rulesync writes. Used by `--frozen`\n * integrity checks to decide whether a prior hash is comparable: any value\n * not matching this regex (e.g. written by the upstream `apm` CLI) is\n * skipped rather than throwing so that cross-tool interop works.\n */\nexport const RULESYNC_CONTENT_HASH_REGEX = /^sha256:[0-9a-f]{64}$/;\n\n/**\n * Single dependency entry in `rulesync-apm.lock.yaml`. Mirrors the subset of the\n * APM v1 lockfile schema that rulesync currently populates. Extra fields\n * from the spec (content_hash, is_dev, virtual_path, ...) are preserved\n * verbatim so that rulesync does not strip them out when re-writing a\n * lockfile produced by `apm` itself.\n */\nconst ApmLockDependencySchema = z.looseObject({\n repo_url: z.string(),\n resolved_commit: optional(\n z\n .string()\n .check(refine((v) => /^[0-9a-f]{40}$/.test(v), \"resolved_commit must be a 40-char hex SHA\")),\n ),\n resolved_ref: optional(z.string()),\n version: optional(z.string()),\n depth: z.int().check(nonnegative()),\n resolved_by: optional(z.string()),\n package_type: z.string(),\n // Intentionally loose: the upstream `apm` CLI may write content_hash values\n // that do not match the strict rulesync format. We accept any string on read\n // so that a lockfile produced by `apm` round-trips through rulesync without\n // throwing. Rulesync itself always writes values matching\n // `RULESYNC_CONTENT_HASH_REGEX`, and `--frozen` integrity checks only\n // enforce the comparison when the recorded hash matches that shape.\n content_hash: optional(z.string()),\n is_dev: optional(z.boolean()),\n deployed_files: z.array(z.string()),\n source: optional(z.string()),\n local_path: optional(z.string()),\n virtual_path: optional(z.string()),\n is_virtual: optional(z.boolean()),\n});\nexport type ApmLockDependency = z.infer<typeof ApmLockDependencySchema>;\n\nconst ApmLockSchema = z.looseObject({\n lockfile_version: z.literal(\"1\"),\n generated_at: z.string(),\n apm_version: z.string(),\n dependencies: z.array(ApmLockDependencySchema),\n mcp_servers: optional(z.array(z.string())),\n});\nexport type ApmLock = z.infer<typeof ApmLockSchema>;\n\nexport function getApmLockPath(projectRoot: string): string {\n return join(projectRoot, APM_LOCKFILE_FILE_NAME);\n}\n\n/**\n * Create an empty lockfile structure. `apm_version` is set to the rulesync\n * compatibility-marker string so downstream tooling can tell this lockfile\n * was produced by rulesync rather than the upstream `apm` CLI.\n *\n * When `existingLock` is provided, all top-level fields from that lock (e.g.\n * `mcp_servers` and any looseObject extras written by the upstream `apm`\n * CLI) are carried forward. `dependencies` is always reset to an empty array\n * and `generated_at` is refreshed; `apm_version` is overwritten by the value\n * passed in `params.apmVersion`.\n */\nexport function createEmptyApmLock(params: {\n apmVersion: string;\n existingLock?: ApmLock | null;\n}): ApmLock {\n const base = params.existingLock ? { ...params.existingLock } : {};\n return {\n ...base,\n lockfile_version: APM_LOCKFILE_VERSION,\n generated_at: new Date().toISOString(),\n apm_version: params.apmVersion,\n dependencies: [],\n };\n}\n\n/**\n * Parse `rulesync-apm.lock.yaml` content into an `ApmLock`. Returns `null` when the\n * content is absent / empty / non-YAML-object so callers can treat the lock\n * as missing. A *structurally* present lockfile that fails schema validation\n * throws a descriptive error rather than being silently dropped — silently\n * discarding a corrupt lockfile would erase previously pinned commits.\n */\nexport function parseApmLock(content: string): ApmLock | null {\n if (!content.trim()) {\n return null;\n }\n let loaded: unknown;\n try {\n loaded = loadYaml(content);\n } catch {\n return null;\n }\n if (!loaded || typeof loaded !== \"object\") {\n return null;\n }\n const parsed = ApmLockSchema.safeParse(loaded);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => ` - ${issue.path.join(\".\") || \"<root>\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid ${APM_LOCKFILE_FILE_NAME}:\\n${issues}`);\n }\n return parsed.data;\n}\n\nexport async function readApmLock(projectRoot: string): Promise<ApmLock | null> {\n const path = getApmLockPath(projectRoot);\n if (!(await fileExists(path))) {\n return null;\n }\n const content = await readFileContent(path);\n return parseApmLock(content);\n}\n\nexport async function writeApmLock(params: { projectRoot: string; lock: ApmLock }): Promise<void> {\n const path = getApmLockPath(params.projectRoot);\n const content = serializeApmLock(params.lock);\n await writeFileContent(path, content);\n}\n\nexport function serializeApmLock(lock: ApmLock): string {\n // `noRefs: true` avoids YAML anchors/aliases; `lineWidth: -1` keeps long\n // URLs on a single line so the file stays diff-friendly.\n return dump(lock, { noRefs: true, lineWidth: -1, sortKeys: false });\n}\n\n/**\n * Find the locked entry for a repo_url. GitHub routes `owner/repo` path\n * components case-insensitively, so the comparison here is case-insensitive\n * to match `apm-manifest.ts` canonicalization and avoid frozen-mode false\n * positives when users re-case their manifest.\n */\nexport function findApmLockDependency(\n lock: ApmLock,\n repoUrl: string,\n): ApmLockDependency | undefined {\n const target = repoUrl.toLowerCase();\n return lock.dependencies.find((d) => d.repo_url.toLowerCase() === target);\n}\n","import { join } from \"node:path\";\n\nimport { optional, z } from \"zod/mini\";\n\nimport { fileExists, readFileContent } from \"../../utils/file.js\";\nimport { loadYaml } from \"../../utils/yaml.js\";\n\nconst APM_MANIFEST_FILE_NAME = \"apm.yml\";\n\n/**\n * Parsed representation of a single APM `dependencies.apm` entry after\n * normalization. Every accepted input form (string shorthand, object form,\n * HTTPS URL) lands here.\n */\nexport type ApmDependency = {\n /** Canonical git URL. Always an HTTPS URL for the first iteration. */\n gitUrl: string;\n /** GitHub owner (extracted for use with the REST client). */\n owner: string;\n /** GitHub repo. */\n repo: string;\n /**\n * Optional ref (tag, branch, or commit SHA). Absent means \"resolve against\n * the repository's default branch\".\n */\n ref?: string;\n /**\n * Optional virtual sub-directory within the repository. When present the\n * install layout is rooted at this path.\n */\n path?: string;\n /**\n * Optional alias used to override the local install directory name.\n */\n alias?: string;\n};\n\nconst ApmObjectDependencySchema = z.looseObject({\n git: optional(z.string()),\n source: optional(z.string()),\n path: optional(z.string()),\n ref: optional(z.string()),\n alias: optional(z.string()),\n});\n\nconst ApmDependencyInputSchema = z.union([z.string(), ApmObjectDependencySchema]);\n\nconst ApmManifestSchema = z.looseObject({\n name: optional(z.string()),\n version: optional(z.string()),\n dependencies: optional(\n z.looseObject({\n apm: optional(z.array(ApmDependencyInputSchema)),\n }),\n ),\n});\n\nexport type ApmManifest = {\n name?: string;\n version?: string;\n dependencies: ApmDependency[];\n};\n\n/**\n * Return the absolute path to the project's `apm.yml`.\n */\nexport function getApmManifestPath(projectRoot: string): string {\n return join(projectRoot, APM_MANIFEST_FILE_NAME);\n}\n\n/**\n * True if `apm.yml` exists at the given base directory.\n */\nexport async function apmManifestExists(projectRoot: string): Promise<boolean> {\n return fileExists(getApmManifestPath(projectRoot));\n}\n\n/**\n * Parse `apm.yml` content. Throws with a descriptive error when parsing\n * or any dependency entry fails normalization.\n */\nexport function parseApmManifest(content: string): ApmManifest {\n const loaded = loadYaml(content);\n if (loaded === undefined || loaded === null) {\n return { dependencies: [] };\n }\n const parsed = ApmManifestSchema.safeParse(loaded);\n if (!parsed.success) {\n throw new Error(`Invalid apm.yml: ${parsed.error.message}`);\n }\n const raw = parsed.data;\n const rawDeps = raw.dependencies?.apm ?? [];\n const dependencies: ApmDependency[] = rawDeps.map((entry, index) =>\n normalizeDependency(entry, index),\n );\n return {\n name: raw.name,\n version: raw.version,\n dependencies,\n };\n}\n\n/**\n * Read and parse `apm.yml` from disk.\n */\nexport async function readApmManifest(projectRoot: string): Promise<ApmManifest> {\n const path = getApmManifestPath(projectRoot);\n const content = await readFileContent(path);\n return parseApmManifest(content);\n}\n\nfunction normalizeDependency(\n entry: string | z.infer<typeof ApmObjectDependencySchema>,\n index: number,\n): ApmDependency {\n if (typeof entry === \"string\") {\n return normalizeStringDependency(entry, index);\n }\n const gitUrl = entry.git ?? entry.source;\n if (!gitUrl) {\n throw new Error(\n `apm.yml dependency #${index + 1}: object form requires a \"git\" field. Received: ${JSON.stringify(entry)}.`,\n );\n }\n const parsedUrl = parseHttpsGitHubUrl(gitUrl);\n if (!parsedUrl) {\n throw new Error(\n `apm.yml dependency #${index + 1}: unsupported git URL \"${gitUrl}\". Only HTTPS GitHub URLs (https://github.com/owner/repo[.git]) are supported in this version. SSH, GitLab, Bitbucket, and other hosts are not yet supported.`,\n );\n }\n if (entry.path !== undefined) {\n validateSubPath(entry.path, index);\n }\n return {\n gitUrl: parsedUrl.gitUrl,\n owner: parsedUrl.owner,\n repo: parsedUrl.repo,\n ref: entry.ref,\n path: entry.path,\n alias: entry.alias,\n };\n}\n\n/**\n * Reject `dep.path` values that could escape the repository root or be\n * interpreted as an absolute path on the remote tree.\n */\nfunction validateSubPath(subPath: string, index: number): void {\n if (subPath === \"\" || subPath.startsWith(\"/\") || subPath.startsWith(\"\\\\\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: \"path\" must be a non-empty relative path without a leading slash. Received: ${JSON.stringify(subPath)}.`,\n );\n }\n const segments = subPath.split(/[/\\\\]/);\n if (segments.includes(\"..\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: \"path\" must not contain \"..\" segments. Received: ${JSON.stringify(subPath)}.`,\n );\n }\n}\n\nfunction normalizeStringDependency(entry: string, index: number): ApmDependency {\n const trimmed = entry.trim();\n if (!trimmed) {\n throw new Error(`apm.yml dependency #${index + 1}: entry must be a non-empty string.`);\n }\n rejectUnsupportedShorthand(trimmed, index);\n\n if (trimmed.startsWith(\"https://\")) {\n const [urlPart, refPart] = splitOnFirst(trimmed, \"#\");\n const parsed = parseHttpsGitHubUrl(urlPart);\n if (!parsed) {\n throw new Error(\n `apm.yml dependency #${index + 1}: unsupported URL \"${urlPart}\". Only HTTPS GitHub URLs (https://github.com/owner/repo[.git]) are supported in this version.`,\n );\n }\n return {\n gitUrl: parsed.gitUrl,\n owner: parsed.owner,\n repo: parsed.repo,\n ref: refPart || undefined,\n };\n }\n\n const [ownerRepo, refPart] = splitOnFirst(trimmed, \"#\");\n const slashIndex = ownerRepo.indexOf(\"/\");\n if (slashIndex === -1 || slashIndex === 0 || slashIndex === ownerRepo.length - 1) {\n throw new Error(\n `apm.yml dependency #${index + 1}: shorthand \"${entry}\" must be in the form \"owner/repo[#ref]\".`,\n );\n }\n if (ownerRepo.includes(\"/\", slashIndex + 1)) {\n throw new Error(\n `apm.yml dependency #${index + 1}: FQDN shorthand or sub-path shorthand (\"${entry}\") is not yet supported. Use the object form with an explicit \"git\" URL.`,\n );\n }\n // Canonicalize owner/repo to lower-case for case-insensitive matching.\n const owner = ownerRepo.substring(0, slashIndex).toLowerCase();\n const repo = ownerRepo.substring(slashIndex + 1).toLowerCase();\n return {\n gitUrl: `https://github.com/${owner}/${repo}.git`,\n owner,\n repo,\n ref: refPart || undefined,\n };\n}\n\nfunction rejectUnsupportedShorthand(entry: string, index: number): void {\n if (entry.startsWith(\"./\") || entry.startsWith(\"../\") || entry.startsWith(\"/\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: local path dependencies (\"${entry}\") are not yet supported by rulesync.`,\n );\n }\n if (entry.startsWith(\"git@\") || entry.startsWith(\"ssh://\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: SSH URL dependencies (\"${entry}\") are not yet supported. Use an HTTPS GitHub URL.`,\n );\n }\n if (entry.includes(\"@marketplace\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: APM marketplace dependencies (\"${entry}\") are not yet supported.`,\n );\n }\n}\n\nfunction parseHttpsGitHubUrl(url: string): { gitUrl: string; owner: string; repo: string } | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n const host = parsed.hostname.toLowerCase();\n if (host !== \"github.com\" && host !== \"www.github.com\") {\n return null;\n }\n const segments = parsed.pathname.split(\"/\").filter(Boolean);\n if (segments.length < 2) {\n return null;\n }\n const rawOwner = segments[0];\n const rawRepo = segments[1];\n if (!rawOwner || !rawRepo) {\n return null;\n }\n // GitHub treats owner/repo names case-insensitively for routing. Canonicalize\n // to lower-case so that lockfile comparisons and frozen-mode checks are not\n // tripped up by a user re-casing their manifest.\n const owner = rawOwner.toLowerCase();\n const repo = rawRepo.replace(/\\.git$/, \"\").toLowerCase();\n return {\n gitUrl: `https://github.com/${owner}/${repo}.git`,\n owner,\n repo,\n };\n}\n\nfunction splitOnFirst(input: string, separator: string): [string, string | undefined] {\n const idx = input.indexOf(separator);\n if (idx === -1) return [input, undefined];\n return [input.substring(0, idx), input.substring(idx + 1)];\n}\n","import { createHash } from \"node:crypto\";\nimport { join, posix } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport { FETCH_CONCURRENCY_LIMIT, MAX_FILE_SIZE } from \"../../constants/rulesync-paths.js\";\nimport type { GitHubFileEntry } from \"../../types/fetch.js\";\nimport { formatError } from \"../../utils/error.js\";\nimport { checkPathTraversal, removeFile, toPosixPath, writeFileContent } from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { GitHubClient, GitHubClientError, logGitHubAuthHints } from \"../github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"../github-utils.js\";\nimport {\n type ApmLock,\n type ApmLockDependency,\n createEmptyApmLock,\n findApmLockDependency,\n readApmLock,\n RULESYNC_CONTENT_HASH_REGEX,\n writeApmLock,\n} from \"./apm-lock.js\";\nimport { type ApmDependency, readApmManifest } from \"./apm-manifest.js\";\n\n/** APM compatibility marker written into `apm_version` when rulesync writes a lockfile. */\nconst RULESYNC_APM_COMPAT_VERSION = \"rulesync-compat/0.1\";\n\n/**\n * Primitives the first iteration deploys. Ordered by scan priority.\n * Each entry maps a package-relative source directory (rooted at the\n * dependency's `path` if given, else the repo root) to the on-disk\n * deployment directory. This matches the default APM layout when the\n * github-copilot host is present.\n */\nconst APM_PRIMITIVES: Array<{ sourceDir: string; deployDir: string; packageType: string }> = [\n {\n sourceDir: \".apm/instructions\",\n deployDir: \".github/instructions\",\n packageType: \"apm_package\",\n },\n {\n sourceDir: \".apm/skills\",\n deployDir: \".github/skills\",\n packageType: \"apm_package\",\n },\n];\n\nexport type ApmInstallOptions = {\n /** Force re-resolve all refs, ignoring the lockfile. */\n update?: boolean;\n /** Fail if the lockfile is missing or out of sync (for CI). */\n frozen?: boolean;\n /** GitHub token for private repositories. */\n token?: string;\n};\n\nexport type ApmInstallResult = {\n dependenciesProcessed: number;\n deployedFileCount: number;\n failedDependencyCount: number;\n};\n\n/**\n * Entry point for `rulesync install --mode apm`. Reads `apm.yml`, resolves\n * every declared APM dependency, fetches the subset of primitives rulesync\n * currently understands (Instructions and Skills), and updates `rulesync-apm.lock.yaml`.\n */\nexport async function installApm(params: {\n projectRoot: string;\n options?: ApmInstallOptions;\n logger: Logger;\n}): Promise<ApmInstallResult> {\n const { projectRoot, options = {}, logger } = params;\n\n const manifest = await readApmManifest(projectRoot);\n if (manifest.dependencies.length === 0) {\n logger.warn(\"apm.yml has no dependencies.apm entries. Nothing to install.\");\n return { dependenciesProcessed: 0, deployedFileCount: 0, failedDependencyCount: 0 };\n }\n\n const existingLock = await readApmLock(projectRoot);\n if (options.frozen) {\n assertFrozenLockCoversManifest({ existingLock, dependencies: manifest.dependencies });\n }\n\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n const newLock: ApmLock = createEmptyApmLock({\n apmVersion: existingLock?.apm_version ?? RULESYNC_APM_COMPAT_VERSION,\n existingLock,\n });\n\n // Dependencies are independent, so install them in parallel. The within-dep\n // tree walk is already rate-limited by the shared FETCH_CONCURRENCY_LIMIT\n // semaphore, so top-level parallelism is bounded naturally.\n //\n // Semantics:\n // frozen=true — any failure aborts the whole install (Promise.all\n // rejects on the first rejection).\n // frozen=false — each dep's promise resolves to a result object so that\n // one failing dep does not abort the others.\n type DepResult =\n | { status: \"ok\"; lockEntry: ApmLockDependency; deployedCount: number }\n | { status: \"failed\"; previous: ApmLockDependency | undefined };\n\n const frozen = options.frozen ?? false;\n\n const runOne = async (dep: ApmDependency): Promise<DepResult> => {\n const installed = await installDependency({\n dep,\n client,\n semaphore,\n projectRoot,\n existingLock,\n frozen,\n update: options.update ?? false,\n logger,\n });\n return {\n status: \"ok\",\n lockEntry: installed.lockEntry,\n deployedCount: installed.deployedFiles.length,\n };\n };\n\n const results: DepResult[] = frozen\n ? await Promise.all(manifest.dependencies.map(runOne))\n : await Promise.all(\n manifest.dependencies.map(async (dep): Promise<DepResult> => {\n try {\n return await runOne(dep);\n } catch (error) {\n logger.error(`Failed to install apm dependency \"${dep.gitUrl}\": ${formatError(error)}`);\n if (error instanceof GitHubClientError) {\n logGitHubAuthHints({ error, logger });\n }\n // Preserve the prior lock entry for failed deps so that a\n // transient network error does not destroy a previously pinned\n // commit SHA. We return it rather than pushing here so that the\n // post-loop pushes preserved entries in manifest order, not in\n // promise-completion order.\n const previous = existingLock\n ? findApmLockDependency(existingLock, canonicalRepoUrl(dep))\n : undefined;\n return { status: \"failed\", previous };\n }\n }),\n );\n\n let totalDeployed = 0;\n let failedCount = 0;\n // Iterate in manifest order to keep the lockfile deterministic regardless\n // of promise-completion timing.\n for (const result of results) {\n if (result.status === \"ok\") {\n newLock.dependencies.push(result.lockEntry);\n totalDeployed += result.deployedCount;\n } else {\n failedCount += 1;\n if (result.previous) {\n newLock.dependencies.push(result.previous);\n }\n }\n }\n\n // Remove files that were deployed by a previous install but are no longer\n // part of any current dependency's deployed_files. Without this, stale\n // artifacts would accumulate on disk forever as upstream content changes.\n //\n // SECURITY: `deployed_files` is only schema-validated as `z.array(z.string())`,\n // so a hostile lockfile (planted in a repo and processed by CI) could try\n // to make us `removeFile(\"../../etc/passwd\")`. We defense-in-depth guard\n // each entry: (a) reject absolute paths and `..` segments by shape, then\n // (b) run `checkPathTraversal` for the canonical check used on the write\n // path. Offending entries are skipped with a warn log rather than fatal so\n // that a single bad row cannot brick the install.\n if (existingLock) {\n await removeStaleApmFiles({ existingLock, newLock, projectRoot, logger });\n }\n\n // Always rewrite the lockfile (except under --frozen, which is a verify-only\n // mode). Even on a partially successful install we persist the union of\n // newly pinned entries and preserved previous entries so that first-ever\n // runs with mixed results still record the successful pins.\n if (!frozen) {\n newLock.generated_at = new Date().toISOString();\n await writeApmLock({ projectRoot, lock: newLock });\n if (failedCount === 0) {\n logger.debug(\"rulesync-apm.lock.yaml updated.\");\n } else {\n logger.warn(\n `rulesync-apm.lock.yaml written with partially successful installs (${failedCount} dep(s) failed).`,\n );\n }\n }\n\n return {\n dependenciesProcessed: manifest.dependencies.length,\n deployedFileCount: totalDeployed,\n failedDependencyCount: failedCount,\n };\n}\n\n/**\n * Frozen-mode validation: the lockfile must exist, cover every manifest\n * dependency, and not have drifted from any declared `ref`. Throws with\n * remediation guidance on the first failing check (preserving the original\n * order: missing-lock, missing-entries, then ref drift).\n */\nfunction assertFrozenLockCoversManifest(params: {\n existingLock: ApmLock | null;\n dependencies: ApmDependency[];\n}): asserts params is { existingLock: ApmLock; dependencies: ApmDependency[] } {\n const { existingLock, dependencies } = params;\n if (!existingLock) {\n throw new Error(\n \"Frozen install failed: rulesync-apm.lock.yaml is missing. Run 'rulesync install --mode apm' to create it.\",\n );\n }\n const missing = dependencies.filter(\n (dep) => !findApmLockDependency(existingLock, canonicalRepoUrl(dep)),\n );\n if (missing.length > 0) {\n const names = missing.map((d) => d.gitUrl).join(\", \");\n throw new Error(\n `Frozen install failed: rulesync-apm.lock.yaml is missing entries for: ${names}. Run 'rulesync install --mode apm' to update the lockfile.`,\n );\n }\n // Detect manifest drift: when the user edited `ref` in apm.yml without\n // re-running install, the locked ref no longer matches the declared one.\n // In frozen mode we refuse rather than silently install the locked SHA.\n const drifted = dependencies.filter((dep) => {\n if (dep.ref === undefined) return false;\n const locked = findApmLockDependency(existingLock, canonicalRepoUrl(dep));\n return locked?.resolved_ref !== undefined && locked.resolved_ref !== dep.ref;\n });\n if (drifted.length > 0) {\n const names = drifted\n .map((d) => {\n const locked = findApmLockDependency(existingLock, canonicalRepoUrl(d));\n return `${d.gitUrl} (manifest=${d.ref}, lock=${locked?.resolved_ref})`;\n })\n .join(\", \");\n throw new Error(\n `Frozen install failed: manifest ref does not match rulesync-apm.lock.yaml for: ${names}. Run 'rulesync install --mode apm' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Remove files that a previous install deployed but that are no longer part of\n * any current dependency's `deployed_files`. Each entry is path-traversal\n * hardened (shape check + `checkPathTraversal`) and offending rows are skipped\n * with a warn log rather than fatal.\n */\nasync function removeStaleApmFiles(params: {\n existingLock: ApmLock;\n newLock: ApmLock;\n projectRoot: string;\n logger: Logger;\n}): Promise<void> {\n const { existingLock, newLock, projectRoot, logger } = params;\n const newDeployedFiles = new Set(newLock.dependencies.flatMap((d) => d.deployed_files));\n const toDelete: string[] = [];\n for (const prev of existingLock.dependencies) {\n for (const deployed of prev.deployed_files) {\n if (!newDeployedFiles.has(deployed)) {\n toDelete.push(deployed);\n }\n }\n }\n for (const relativePath of toDelete) {\n if (posix.isAbsolute(relativePath) || relativePath.split(/[/\\\\]/).includes(\"..\")) {\n logger.warn(`Refusing to remove stale apm file with suspicious path: \"${relativePath}\".`);\n continue;\n }\n try {\n checkPathTraversal({ relativePath, intendedRootDir: projectRoot });\n } catch {\n logger.warn(`Refusing to remove stale apm file outside projectRoot: \"${relativePath}\".`);\n continue;\n }\n const absolute = join(projectRoot, relativePath);\n // `removeFile` is best-effort and swallows ENOENT, so missing files are\n // a no-op. This keeps a corrupted partial-install from blowing up here.\n await removeFile(absolute);\n logger.debug(`Removed stale apm file: ${relativePath}`);\n }\n}\n\nasync function installDependency(params: {\n dep: ApmDependency;\n client: GitHubClient;\n semaphore: Semaphore;\n projectRoot: string;\n existingLock: ApmLock | null;\n frozen: boolean;\n update: boolean;\n logger: Logger;\n}): Promise<{ lockEntry: ApmLockDependency; deployedFiles: string[] }> {\n const { dep, client, semaphore, projectRoot, existingLock, frozen, update, logger } = params;\n const repoUrl = canonicalRepoUrl(dep);\n const locked = existingLock ? findApmLockDependency(existingLock, repoUrl) : undefined;\n\n let resolvedRef: string;\n let resolvedSha: string;\n if (locked && !update && locked.resolved_commit && locked.resolved_ref) {\n resolvedRef = locked.resolved_ref;\n resolvedSha = locked.resolved_commit;\n logger.debug(`Using locked commit for ${repoUrl}: ${resolvedSha}`);\n } else {\n resolvedRef = dep.ref ?? (await client.getDefaultBranch(dep.owner, dep.repo));\n resolvedSha = await client.resolveRefToSha(dep.owner, dep.repo, resolvedRef);\n logger.debug(`Resolved ${repoUrl} ref \"${resolvedRef}\" -> ${resolvedSha}`);\n }\n\n // Collect (path, content) pairs before writing to disk. This lets us hash\n // them up-front and, under --frozen, refuse to overwrite good files with\n // tampered bytes. Under non-frozen we still write as we go for incremental\n // progress feedback on large dep trees.\n const deployed: Array<{ path: string; content: string }> = [];\n for (const primitive of APM_PRIMITIVES) {\n const remoteBase = dep.path\n ? toPosixPath(posix.join(dep.path, primitive.sourceDir))\n : primitive.sourceDir;\n const files = await listPrimitiveFiles({\n client,\n semaphore,\n owner: dep.owner,\n repo: dep.repo,\n ref: resolvedSha,\n remoteBase,\n logger,\n });\n if (files.length === 0) continue;\n\n await collectPrimitiveDeployments({\n dep,\n client,\n semaphore,\n projectRoot,\n primitive,\n remoteBase,\n files,\n resolvedSha,\n repoUrl,\n frozen,\n deployed,\n logger,\n });\n }\n\n deployed.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n const deployedFiles = deployed.map((d) => d.path);\n const contentHash = computeContentHash(deployed);\n\n assertFrozenContentHashMatches({ frozen, locked, contentHash, repoUrl, logger });\n\n // Under --frozen we deferred all writes until after the hash check passed.\n if (frozen) {\n for (const { path: deployRelative, content } of deployed) {\n await writeFileContent(join(projectRoot, deployRelative), content);\n }\n }\n\n const lockEntry: ApmLockDependency = {\n repo_url: repoUrl,\n resolved_commit: resolvedSha,\n resolved_ref: resolvedRef,\n depth: 1,\n package_type: \"apm_package\",\n content_hash: contentHash,\n deployed_files: deployedFiles,\n };\n if (dep.path) {\n lockEntry.virtual_path = dep.path;\n }\n\n logger.info(`Installed ${deployedFiles.length} file(s) from ${repoUrl}@${shortSha(resolvedSha)}`);\n\n return { lockEntry, deployedFiles };\n}\n\n/**\n * Fetch and validate the files for a single primitive directory, appending the\n * deployable (path, content) pairs to `deployed`. Oversized or out-of-bounds\n * files are skipped with a warn log; under non-frozen mode bytes are written to\n * disk as they are collected.\n */\nasync function collectPrimitiveDeployments(params: {\n dep: ApmDependency;\n client: GitHubClient;\n semaphore: Semaphore;\n projectRoot: string;\n primitive: (typeof APM_PRIMITIVES)[number];\n remoteBase: string;\n files: GitHubFileEntry[];\n resolvedSha: string;\n repoUrl: string;\n frozen: boolean;\n deployed: Array<{ path: string; content: string }>;\n logger: Logger;\n}): Promise<void> {\n const {\n dep,\n client,\n semaphore,\n projectRoot,\n primitive,\n remoteBase,\n files,\n resolvedSha,\n repoUrl,\n frozen,\n deployed,\n logger,\n } = params;\n\n for (const file of files) {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${repoUrl}: ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n const relativeToBase = posix.relative(remoteBase, toPosixPath(file.path));\n if (!relativeToBase || relativeToBase.startsWith(\"..\") || posix.isAbsolute(relativeToBase)) {\n logger.warn(`Skipping \"${file.path}\" from ${repoUrl}: resolved outside of \"${remoteBase}\".`);\n continue;\n }\n const deployRelative = toPosixPath(join(primitive.deployDir, relativeToBase));\n checkPathTraversal({\n relativePath: deployRelative,\n intendedRootDir: projectRoot,\n });\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(dep.owner, dep.repo, file.path, resolvedSha),\n );\n // The tree-listing size can lie (LFS pointers, filter-driver output),\n // so enforce the cap on the fetched bytes as well.\n const byteLength = Buffer.byteLength(content, \"utf8\");\n if (byteLength > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${repoUrl}: fetched ${(byteLength / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n deployed.push({ path: deployRelative, content });\n if (!frozen) {\n await writeFileContent(join(projectRoot, deployRelative), content);\n }\n }\n}\n\n/**\n * Verify integrity against the lockfile when running frozen and the prior\n * lock recorded a hash rulesync itself wrote. A mismatch means either the\n * upstream content moved under the same SHA (unlikely with git) or someone\n * tampered with the lockfile / deployed files. We do this *before* writing\n * anything to disk under --frozen so that tampered bytes never hit the\n * filesystem.\n *\n * If the recorded hash does not match the rulesync format (e.g. the\n * lockfile was produced by the upstream `apm` CLI which writes a different\n * shape), we skip the integrity check rather than fail — the commit SHA\n * pin is still enforced, and this preserves interop for users migrating\n * from `apm` to `rulesync install --mode apm`.\n */\nfunction assertFrozenContentHashMatches(params: {\n frozen: boolean;\n locked: ApmLockDependency | undefined;\n contentHash: string;\n repoUrl: string;\n logger: Logger;\n}): void {\n const { frozen, locked, contentHash, repoUrl, logger } = params;\n if (frozen && locked?.content_hash) {\n if (RULESYNC_CONTENT_HASH_REGEX.test(locked.content_hash)) {\n if (locked.content_hash !== contentHash) {\n throw new Error(\n `content_hash mismatch for ${repoUrl}: lock=${locked.content_hash} computed=${contentHash}. Refuse to trust the deployment under --frozen.`,\n );\n }\n } else {\n logger.debug(\n `Skipping content_hash integrity check for ${repoUrl}: recorded hash \"${locked.content_hash}\" was not written by rulesync.`,\n );\n }\n }\n}\n\n/**\n * SHA-256 over a canonical, order-independent representation of the deployed\n * files. Written into `content_hash` so that `--frozen` installs can refuse\n * to trust tampered output.\n */\nfunction computeContentHash(files: Array<{ path: string; content: string }>): string {\n const hash = createHash(\"sha256\");\n for (const { path, content } of files) {\n hash.update(path);\n hash.update(\"\\0\");\n hash.update(content);\n hash.update(\"\\0\");\n }\n return `sha256:${hash.digest(\"hex\")}`;\n}\n\nasync function listPrimitiveFiles(params: {\n client: GitHubClient;\n semaphore: Semaphore;\n owner: string;\n repo: string;\n ref: string;\n remoteBase: string;\n logger: Logger;\n}): Promise<GitHubFileEntry[]> {\n const { client, semaphore, owner, repo, ref, remoteBase, logger } = params;\n try {\n return await listDirectoryRecursive({\n client,\n owner,\n repo,\n path: remoteBase,\n ref,\n semaphore,\n });\n } catch (error) {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n logger.debug(`No ${remoteBase}/ in ${owner}/${repo}, skipping.`);\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Canonical repo_url written into the lockfile. We always use the HTTPS form\n * without a trailing `.git` so that lock files round-trip deterministically\n * regardless of whether the manifest referenced the repo with or without\n * the suffix.\n */\nfunction canonicalRepoUrl(dep: ApmDependency): string {\n return `https://github.com/${dep.owner}/${dep.repo}`;\n}\n\nfunction shortSha(sha: string): string {\n return sha.substring(0, 7);\n}\n","import { dump } from \"js-yaml\";\n\nimport { loadYaml } from \"../../utils/yaml.js\";\n\nconst FRONTMATTER_FENCE = \"---\";\n\n/**\n * Parses YAML frontmatter at the head of a SKILL.md, sets/overwrites the\n * three provenance keys (`source`, `repository`, `ref`), and re-serializes.\n *\n * If the file has no frontmatter block, a fresh one is prepended with only\n * the provenance keys + the original body. All other existing frontmatter\n * keys are preserved verbatim (the merge is a shallow object spread on the\n * loaded YAML).\n *\n * Throws `Error(\"invalid frontmatter\")` when an `---` fenced block exists\n * but its body is not a YAML object (e.g. malformed YAML, or a list/scalar\n * at the top level). Callers may choose to fall back to \"prepend fresh\" on\n * this error, but the function itself does not silently rewrite — silently\n * dropping a corrupted frontmatter could destroy user metadata.\n */\nexport function injectSourceMetadata(params: {\n content: string;\n source: string;\n repository: string;\n ref: string;\n}): string {\n const { content, source, repository, ref } = params;\n const provenance = { source, repository, ref };\n\n // Detect the opening fence in both LF (`---\\n`) and CRLF (`---\\r\\n`) forms.\n // SKILL.md files authored on Windows or by editors that preserve CRLF must\n // round-trip cleanly — without this branch the existing frontmatter would\n // be buried inside a fresh provenance block on the first install.\n let openFenceLen: number;\n if (content.startsWith(`${FRONTMATTER_FENCE}\\r\\n`)) {\n openFenceLen = 5;\n } else if (content.startsWith(`${FRONTMATTER_FENCE}\\n`)) {\n openFenceLen = 4;\n } else if (content === FRONTMATTER_FENCE) {\n openFenceLen = 3;\n } else {\n // No frontmatter block. Prepend a fresh one with just the provenance keys.\n const yaml = dump(provenance, { noRefs: true, lineWidth: -1, sortKeys: false });\n return `${FRONTMATTER_FENCE}\\n${yaml}${FRONTMATTER_FENCE}\\n${content}`;\n }\n\n // Body starts immediately after the opening fence.\n const afterOpen = content.substring(openFenceLen);\n\n // Closing fence forms we accept:\n // - `---` immediately at the start of the body (i.e. `---\\n---\\n...`,\n // which yields an empty frontmatter block).\n // - `\\n---` followed by a newline OR end-of-file (the trailing newline\n // after the closing `---` is optional so the fence may sit at EOF).\n let fmBody: string;\n let rest: string;\n if (afterOpen.startsWith(\"---\\n\") || afterOpen.startsWith(\"---\\r\\n\") || afterOpen === \"---\") {\n fmBody = \"\";\n const fenceLen = afterOpen.startsWith(\"---\\r\\n\") ? 5 : afterOpen === \"---\" ? 3 : 4;\n rest = afterOpen.substring(fenceLen);\n } else {\n const match = /\\n---(\\r?\\n|$)/.exec(afterOpen);\n if (!match) {\n // The file starts with `---\\n` but there is no closing `---` line. We\n // refuse to guess where the frontmatter ends; treat as invalid so the\n // caller can decide whether to fall back.\n throw new Error(\"invalid frontmatter\");\n }\n fmBody = afterOpen.substring(0, match.index);\n rest = afterOpen.substring(match.index + match[0].length);\n }\n\n let loaded: unknown;\n try {\n loaded = loadYaml(fmBody);\n } catch {\n throw new Error(\"invalid frontmatter\");\n }\n\n if (loaded === null || loaded === undefined) {\n // Empty frontmatter block (`---\\n---\\n...`). Use only provenance.\n const yaml = dump(provenance, { noRefs: true, lineWidth: -1, sortKeys: false });\n return `${FRONTMATTER_FENCE}\\n${yaml}${FRONTMATTER_FENCE}\\n${rest}`;\n }\n if (typeof loaded !== \"object\" || Array.isArray(loaded)) {\n throw new Error(\"invalid frontmatter\");\n }\n\n // Shallow merge: existing keys preserved, provenance keys overwritten.\n const existing = loaded as Record<string, unknown>;\n const merged: Record<string, unknown> = {\n ...existing,\n ...provenance,\n };\n const yaml = dump(merged, { noRefs: true, lineWidth: -1, sortKeys: false });\n return `${FRONTMATTER_FENCE}\\n${yaml}${FRONTMATTER_FENCE}\\n${rest}`;\n}\n","import { join } from \"node:path\";\n\nimport { dump } from \"js-yaml\";\nimport { optional, refine, z } from \"zod/mini\";\n\nimport { fileExists, readFileContent, writeFileContent } from \"../../utils/file.js\";\nimport { loadYaml } from \"../../utils/yaml.js\";\n\n/**\n * Filename of the rulesync-managed gh-skill-compatible lockfile. Distinct\n * from the rulesync sources lockfile (`rulesync.lock`) and from the\n * apm-mode lockfile (`rulesync-apm.lock.yaml`) so the three install modes\n * never fight over the same file.\n */\nconst GH_LOCKFILE_FILE_NAME = \"rulesync-gh.lock.yaml\";\nexport const GH_LOCKFILE_VERSION = \"1\" as const;\n\n/**\n * Shape of content_hash values that rulesync writes for gh installs. Same\n * format as the apm-mode hash so callers can reuse the integrity check\n * conventions; under `--frozen` only values matching this regex are\n * considered comparable.\n */\nexport const RULESYNC_CONTENT_HASH_REGEX = /^sha256:[0-9a-f]{64}$/;\n\nconst ScopeSchema = z.enum([\"project\", \"user\"]);\n\n/**\n * Single installation entry in `rulesync-gh.lock.yaml`. Each entry pins one\n * skill from one source under one (agent, scope) pair — matching the gh CLI\n * model where `gh skill install` deploys exactly one skill at a time.\n */\nconst GhLockInstallationSchema = z.looseObject({\n source: z.string(),\n owner: z.string(),\n repo: z.string(),\n agent: z.string(),\n scope: ScopeSchema,\n skill: z.string(),\n requested_ref: optional(z.string()),\n resolved_ref: z.string(),\n resolved_commit: z\n .string()\n .check(refine((v) => /^[0-9a-f]{40}$/.test(v), \"resolved_commit must be a 40-char hex SHA\")),\n install_dir: z.string(),\n deployed_files: z.array(z.string()),\n content_hash: optional(z.string()),\n});\nexport type GhLockInstallation = z.infer<typeof GhLockInstallationSchema>;\n\nconst GhLockSchema = z.looseObject({\n lockfile_version: z.literal(\"1\"),\n generated_at: z.string(),\n installations: z.array(GhLockInstallationSchema),\n});\nexport type GhLock = z.infer<typeof GhLockSchema>;\n\nexport function getGhLockPath(projectRoot: string): string {\n return join(projectRoot, GH_LOCKFILE_FILE_NAME);\n}\n\n/**\n * Create an empty gh lockfile structure. When `existingLock` is provided,\n * top-level looseObject extras are carried forward so unknown fields (added\n * by future tools or other lockfile producers) round-trip cleanly.\n */\nexport function createEmptyGhLock(params?: { existingLock?: GhLock | null }): GhLock {\n const base = params?.existingLock ? { ...params.existingLock } : {};\n return {\n ...base,\n lockfile_version: GH_LOCKFILE_VERSION,\n generated_at: new Date().toISOString(),\n installations: [],\n };\n}\n\n/**\n * Parse `rulesync-gh.lock.yaml` content into a `GhLock`. Returns `null` for\n * empty / non-YAML-object content so callers can treat the lockfile as\n * missing. A *structurally* present lockfile that fails schema validation\n * throws, rather than silently dropping previously pinned entries.\n */\nexport function parseGhLock(content: string): GhLock | null {\n if (!content.trim()) {\n return null;\n }\n let loaded: unknown;\n try {\n loaded = loadYaml(content);\n } catch {\n return null;\n }\n if (!loaded || typeof loaded !== \"object\") {\n return null;\n }\n const parsed = GhLockSchema.safeParse(loaded);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => ` - ${issue.path.join(\".\") || \"<root>\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid ${GH_LOCKFILE_FILE_NAME}:\\n${issues}`);\n }\n return parsed.data;\n}\n\nexport async function readGhLock(projectRoot: string): Promise<GhLock | null> {\n const path = getGhLockPath(projectRoot);\n if (!(await fileExists(path))) {\n return null;\n }\n const content = await readFileContent(path);\n return parseGhLock(content);\n}\n\nexport async function writeGhLock(params: { projectRoot: string; lock: GhLock }): Promise<void> {\n const path = getGhLockPath(params.projectRoot);\n const content = serializeGhLock(params.lock);\n await writeFileContent(path, content);\n}\n\nexport function serializeGhLock(lock: GhLock): string {\n // `noRefs: true` avoids YAML anchors/aliases; `lineWidth: -1` keeps long\n // URLs and sha values on a single line so the file stays diff-friendly.\n return dump(lock, { noRefs: true, lineWidth: -1, sortKeys: false });\n}\n\n/**\n * Find the locked installation for a given (source, agent, scope, skill)\n * tuple. Source is matched case-insensitively because GitHub routes\n * `owner/repo` paths case-insensitively.\n */\nexport function findGhLockInstallation(\n lock: GhLock,\n params: { source: string; agent: string; scope: \"project\" | \"user\"; skill: string },\n): GhLockInstallation | undefined {\n const target = params.source.toLowerCase();\n return lock.installations.find(\n (i) =>\n i.source.toLowerCase() === target &&\n i.agent === params.agent &&\n i.scope === params.scope &&\n i.skill === params.skill,\n );\n}\n","import { join } from \"node:path\";\n\nimport { CLAUDECODE_SKILLS_DIR_PATH } from \"../../constants/claudecode-paths.js\";\nimport { getHomeDirectory } from \"../../utils/file.js\";\n\n/**\n * Agents recognized by `--mode gh`. Mirrors the agent list documented for\n * `gh skill install`. The same skill content can be deployed under multiple\n * agent-specific directories simultaneously, one entry per `(agent, scope)`\n * pair in `rulesync.jsonc`.\n */\nexport const GH_AGENTS = [\n \"github-copilot\",\n \"claude-code\",\n \"cursor\",\n \"codex\",\n \"gemini\",\n \"antigravity\",\n] as const;\nexport type GhAgent = (typeof GH_AGENTS)[number];\n\nexport type GhScope = \"project\" | \"user\";\n\n/**\n * Resolve the absolute install directory for a given agent + scope, matching\n * the layout expected by `gh skill install`.\n *\n * Project scope writes inside `projectRoot`. The `github-copilot` agent uses the\n * shared `.agents/skills` directory (the host-agnostic project layout); other\n * agents that share that location (cursor, codex, gemini, antigravity) write\n * to `.agents/skills` for project scope and to their own `.<tool>/skills`\n * directory for user scope. Claude Code is the exception: project and user\n * scope both use `.claude/skills`, just rooted at `projectRoot` vs the home\n * directory respectively.\n */\nexport function resolveGhInstallDir(params: {\n agent: GhAgent;\n scope: GhScope;\n projectRoot: string;\n}): string {\n const { agent, scope, projectRoot } = params;\n const home = scope === \"user\" ? getHomeDirectory() : projectRoot;\n const relative = relativeInstallDirFor({ agent, scope });\n return join(home, relative);\n}\n\n/**\n * Returns the install directory relative to its scope root (projectRoot for\n * project scope, home for user scope). Exposed separately so the lockfile can\n * record the same canonical relative path it deploys to.\n */\nexport function relativeInstallDirFor(params: { agent: GhAgent; scope: GhScope }): string {\n const { agent, scope } = params;\n if (scope === \"project\") {\n if (agent === \"claude-code\") {\n return CLAUDECODE_SKILLS_DIR_PATH;\n }\n // github-copilot and the rest share the shared project layout.\n return join(\".agents\", \"skills\");\n }\n // user scope\n switch (agent) {\n case \"github-copilot\":\n return join(\".copilot\", \"skills\");\n case \"claude-code\":\n return CLAUDECODE_SKILLS_DIR_PATH;\n case \"cursor\":\n return join(\".cursor\", \"skills\");\n case \"codex\":\n return join(\".agents\", \"skills\");\n case \"gemini\":\n return join(\".gemini\", \"skills\");\n case \"antigravity\":\n return join(\".gemini\", \"antigravity\", \"skills\");\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { basename, join, posix } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport type { SourceEntry } from \"../../config/config.js\";\nimport { FETCH_CONCURRENCY_LIMIT, MAX_FILE_SIZE } from \"../../constants/rulesync-paths.js\";\nimport { formatError } from \"../../utils/error.js\";\nimport {\n checkPathTraversal,\n getHomeDirectory,\n removeFile,\n toPosixPath,\n writeFileContent,\n} from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { GitHubClient, GitHubClientError, logGitHubAuthHints } from \"../github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"../github-utils.js\";\nimport { parseSource } from \"../source-parser.js\";\nimport { injectSourceMetadata } from \"./gh-frontmatter.js\";\nimport {\n createEmptyGhLock,\n findGhLockInstallation,\n type GhLock,\n type GhLockInstallation,\n readGhLock,\n RULESYNC_CONTENT_HASH_REGEX,\n writeGhLock,\n} from \"./gh-lock.js\";\nimport { type GhAgent, GH_AGENTS, type GhScope, relativeInstallDirFor } from \"./gh-paths.js\";\n\nconst SKILLS_REMOTE_DIR = \"skills\";\nconst SKILL_FILE_NAME = \"SKILL.md\";\n\nexport type GhInstallOptions = {\n /** Force re-resolve all refs, ignoring the lockfile. */\n update?: boolean;\n /** Fail if the lockfile is missing or out of sync (for CI). */\n frozen?: boolean;\n /** GitHub token for private repositories. */\n token?: string;\n};\n\nexport type GhInstallResult = {\n sourcesProcessed: number;\n installedSkillCount: number;\n failedSourceCount: number;\n};\n\ntype ResolvedSource = {\n entry: SourceEntry;\n owner: string;\n repo: string;\n ref?: string;\n agent: GhAgent;\n scope: GhScope;\n};\n\ntype DeployedFile = {\n /** Relative POSIX path under the install dir's scope root. Recorded in the lockfile. */\n relativeToScopeRoot: string;\n /** Absolute on-disk path where the bytes are written. */\n absolutePath: string;\n content: string;\n};\n\ntype SkillInstallation = {\n installation: GhLockInstallation;\n deployed: DeployedFile[];\n};\n\ntype SourceResult =\n | { status: \"ok\"; installations: SkillInstallation[] }\n | { status: \"failed\"; preserved: GhLockInstallation[] };\n\n/**\n * Entry point for `rulesync install --mode gh`. Reads `sources` from\n * `rulesync.jsonc`, resolves each one against the GitHub API, and deploys\n * each discovered `skills/<name>/` tree under the agent-specific install\n * directory recorded by `resolveGhInstallDir`. Updates `rulesync-gh.lock.yaml`\n * to pin commits and per-skill content hashes.\n */\nexport async function installGh(params: {\n projectRoot: string;\n sources: SourceEntry[];\n options?: GhInstallOptions;\n logger: Logger;\n}): Promise<GhInstallResult> {\n const { projectRoot, sources, options = {}, logger } = params;\n\n if (sources.length === 0) {\n return { sourcesProcessed: 0, installedSkillCount: 0, failedSourceCount: 0 };\n }\n\n // Pre-resolve every source's owner/repo + agent/scope defaults so the\n // frozen-mode coverage check below has a stable view of what installations\n // are required. We do not contact the API yet — that happens per-source.\n const resolvedSources: ResolvedSource[] = sources.map(resolveGhSource);\n\n const existingLock = await readGhLock(projectRoot);\n const frozen = options.frozen ?? false;\n const update = options.update ?? false;\n\n if (frozen && !existingLock) {\n throw new Error(\n \"Frozen install failed: rulesync-gh.lock.yaml is missing. Run 'rulesync install --mode gh' to create it.\",\n );\n }\n\n if (frozen && existingLock) {\n assertFrozenLockCoversSources({ existingLock, resolvedSources });\n }\n\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n const newLock: GhLock = createEmptyGhLock({ existingLock });\n\n const runOne = async (rs: ResolvedSource): Promise<SourceResult> => {\n const installations = await installSource({\n rs,\n client,\n semaphore,\n projectRoot,\n existingLock,\n frozen,\n update,\n logger,\n });\n return { status: \"ok\", installations };\n };\n\n const results: SourceResult[] = frozen\n ? await Promise.all(resolvedSources.map(runOne))\n : await Promise.all(\n resolvedSources.map(async (rs): Promise<SourceResult> => {\n try {\n return await runOne(rs);\n } catch (error) {\n logger.error(`Failed to install gh source \"${rs.entry.source}\": ${formatError(error)}`);\n if (error instanceof GitHubClientError) {\n logGitHubAuthHints({ error, logger });\n }\n // Preserve all prior installations for this source so that a\n // transient error does not erase previously pinned commit SHAs.\n const preserved = existingLock\n ? existingLock.installations.filter(\n (i) => i.source.toLowerCase() === rs.entry.source.toLowerCase(),\n )\n : [];\n return { status: \"failed\", preserved };\n }\n }),\n );\n\n if (frozen) {\n await writeDeferredFrozenFiles(results);\n }\n\n const { totalInstalled, failedCount } = aggregateSourceResults({ results, newLock });\n\n // Stale-file cleanup. Same hardening shape as apm-install.\n if (existingLock) {\n await removeStaleGhFiles({ existingLock, newLock, projectRoot, logger });\n }\n\n if (!frozen) {\n newLock.generated_at = new Date().toISOString();\n await writeGhLock({ projectRoot, lock: newLock });\n if (failedCount === 0) {\n logger.debug(\"rulesync-gh.lock.yaml updated.\");\n } else {\n logger.warn(\n `rulesync-gh.lock.yaml written with partially successful installs (${failedCount} source(s) failed).`,\n );\n }\n }\n\n return {\n sourcesProcessed: sources.length,\n installedSkillCount: totalInstalled,\n failedSourceCount: failedCount,\n };\n}\n\n/**\n * Validate and normalize a single declared source into a ResolvedSource without\n * contacting the API. Rejects non-GitHub providers and the gh-unsupported\n * `transport`/`path` fields, and applies the agent/scope defaults.\n */\nfunction resolveGhSource(entry: SourceEntry): ResolvedSource {\n const parsed = parseSource(entry.source);\n if (parsed.provider !== \"github\") {\n throw new Error(\n `--mode gh only supports GitHub sources. \"${entry.source}\" resolves to provider \"${parsed.provider}\".`,\n );\n }\n // gh mode does not honor `transport` or `path` from the SourceEntry —\n // both are rulesync-mode-only concepts. Silently dropping them would\n // surprise users migrating from --mode rulesync, so reject up-front\n // with a message that names the offending field.\n if (entry.transport !== undefined && entry.transport !== \"github\") {\n throw new Error(\n `--mode gh: field \"transport\" is not supported (got \"${entry.transport}\" for source \"${entry.source}\"). Drop the field or switch to --mode rulesync.`,\n );\n }\n if (entry.path !== undefined) {\n throw new Error(\n `--mode gh: field \"path\" is not supported for source \"${entry.source}\". The remote layout is fixed to \"skills/<name>/SKILL.md\".`,\n );\n }\n const agent = entry.agent ?? \"github-copilot\";\n if (!GH_AGENTS.includes(agent)) {\n throw new Error(\n `--mode gh: unknown agent \"${agent}\" for source \"${entry.source}\". Valid agents: ${GH_AGENTS.join(\", \")}.`,\n );\n }\n const scope: GhScope = entry.scope ?? \"project\";\n return {\n entry,\n owner: parsed.owner,\n repo: parsed.repo,\n ref: entry.ref ?? parsed.ref,\n agent,\n scope,\n };\n}\n\n/**\n * Frozen mode: per-source coverage check plus `ref` drift detection. A\n * brand-new source (no installations at all in the lock) must fail before we\n * contact the GitHub API — both to save quota and to prevent in-flight\n * Promise.all siblings from writing files when another source is going to\n * throw. Per-skill coverage is enforced lazily inside installSource, since that\n * requires API discovery to know which skills exist remotely.\n */\nfunction assertFrozenLockCoversSources(params: {\n existingLock: GhLock;\n resolvedSources: ResolvedSource[];\n}): void {\n const { existingLock, resolvedSources } = params;\n const uncovered: string[] = [];\n for (const rs of resolvedSources) {\n const hasAny = existingLock.installations.some(\n (i) =>\n i.source.toLowerCase() === rs.entry.source.toLowerCase() &&\n i.agent === rs.agent &&\n i.scope === rs.scope,\n );\n if (!hasAny) {\n uncovered.push(`${rs.entry.source} (agent=${rs.agent}, scope=${rs.scope})`);\n }\n }\n if (uncovered.length > 0) {\n throw new Error(\n `Frozen install failed: rulesync-gh.lock.yaml is missing entries for: ${uncovered.join(\", \")}. Run 'rulesync install --mode gh' to update the lockfile.`,\n );\n }\n\n // Detect manifest drift on `ref`: when the user edited `ref` in\n // rulesync.jsonc without re-running install, refuse rather than\n // silently install the locked SHA against a different declared ref.\n const drifted: string[] = [];\n for (const rs of resolvedSources) {\n if (!rs.ref) continue;\n const matches = existingLock.installations.filter(\n (i) => i.source.toLowerCase() === rs.entry.source.toLowerCase(),\n );\n for (const m of matches) {\n if (m.requested_ref !== undefined && m.requested_ref !== rs.ref) {\n drifted.push(`${rs.entry.source} (manifest=${rs.ref}, lock=${m.requested_ref})`);\n break;\n }\n }\n }\n if (drifted.length > 0) {\n throw new Error(\n `Frozen install failed: manifest ref does not match rulesync-gh.lock.yaml for: ${drifted.join(\", \")}. Run 'rulesync install --mode gh' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Frozen-mode deferred writes. `installSource` never touches the disk under\n * --frozen — every write lands here, only after Promise.all has resolved\n * successfully for every source. Without this gate, source A could finish\n * writing its bytes before source B's coverage / integrity check throws,\n * leaving the working tree in a partially-frozen state despite the install\n * reporting failure.\n */\nasync function writeDeferredFrozenFiles(results: SourceResult[]): Promise<void> {\n for (const result of results) {\n if (result.status !== \"ok\") continue;\n for (const inst of result.installations) {\n for (const d of inst.deployed) {\n await writeFileContent(d.absolutePath, d.content);\n }\n }\n }\n}\n\n/**\n * Push each source result's installations (or preserved prior entries on\n * failure) into the new lock, returning the installed and failed counts.\n */\nfunction aggregateSourceResults(params: { results: SourceResult[]; newLock: GhLock }): {\n totalInstalled: number;\n failedCount: number;\n} {\n const { results, newLock } = params;\n let totalInstalled = 0;\n let failedCount = 0;\n for (const result of results) {\n if (result.status === \"ok\") {\n for (const inst of result.installations) {\n newLock.installations.push(inst.installation);\n }\n totalInstalled += result.installations.length;\n } else {\n failedCount += 1;\n for (const preserved of result.preserved) {\n newLock.installations.push(preserved);\n }\n }\n }\n return { totalInstalled, failedCount };\n}\n\n/**\n * Remove files deployed by a previous install that are no longer part of any\n * current installation, keyed by (scope, path) so identically-named files under\n * different scope roots are not conflated.\n */\nasync function removeStaleGhFiles(params: {\n existingLock: GhLock;\n newLock: GhLock;\n projectRoot: string;\n logger: Logger;\n}): Promise<void> {\n const { existingLock, newLock, projectRoot, logger } = params;\n const newDeployed = new Set<string>();\n for (const inst of newLock.installations) {\n for (const file of inst.deployed_files) {\n // Key by (scope, path) so a file in `<home>/.claude/skills/foo` and a\n // file at `<base>/.claude/skills/foo` are not conflated.\n newDeployed.add(`${inst.scope}::${file}`);\n }\n }\n for (const prev of existingLock.installations) {\n for (const deployed of prev.deployed_files) {\n const key = `${prev.scope}::${deployed}`;\n if (newDeployed.has(key)) continue;\n await removeStaleFile({\n relativePath: deployed,\n scope: prev.scope === \"user\" ? \"user\" : \"project\",\n projectRoot,\n logger,\n });\n }\n }\n}\n\nasync function installSource(params: {\n rs: ResolvedSource;\n client: GitHubClient;\n semaphore: Semaphore;\n projectRoot: string;\n existingLock: GhLock | null;\n frozen: boolean;\n update: boolean;\n logger: Logger;\n}): Promise<SkillInstallation[]> {\n const { rs, client, semaphore, projectRoot, existingLock, frozen, update, logger } = params;\n const { entry, owner, repo, agent, scope } = rs;\n const sourceKey = entry.source;\n\n const { resolvedRef, resolvedSha, usedTag } = await resolveGhRef({\n rs,\n client,\n owner,\n repo,\n sourceKey,\n logger,\n });\n\n // Discover skills under `skills/`.\n const validatedSkills = await discoverValidatedSkills({\n client,\n semaphore,\n owner,\n repo,\n resolvedSha,\n sourceKey,\n logger,\n });\n if (validatedSkills === null) {\n return [];\n }\n\n // Apply the explicit skill filter when provided.\n const selected = selectSkills({ validatedSkills, entry, sourceKey, logger });\n\n // Frozen-mode coverage check (per-skill). Only enforceable now that we know\n // the requested skill set.\n if (frozen && existingLock) {\n assertFrozenSkillCoverage({ selected, existingLock, sourceKey, agent, scope });\n }\n\n const results: SkillInstallation[] = [];\n const installRelDir = relativeInstallDirFor({ agent, scope });\n const scopeRoot = scope === \"user\" ? getHomeDirectory() : projectRoot;\n\n // Source URL recorded in injected frontmatter. Mirrors the canonical form\n // used by `gh skill install`.\n const sourceUrl = `https://github.com/${owner}/${repo}`;\n const repository = `${owner}/${repo}`;\n // gh records the *resolved* ref (the tag name when one was used, else the\n // commit SHA) into the SKILL.md frontmatter so the deployed file has a\n // human-readable provenance hint.\n const provenanceRef = usedTag ? resolvedRef : resolvedSha;\n\n for (const sk of selected) {\n const locked =\n existingLock && !update\n ? findGhLockInstallation(existingLock, {\n source: sourceKey,\n agent,\n scope,\n skill: sk.name,\n })\n : undefined;\n\n // Recursively list this skill's tree.\n const allFiles = await listDirectoryRecursive({\n client,\n owner,\n repo,\n path: sk.path,\n ref: resolvedSha,\n semaphore,\n });\n\n const deployed = await buildSkillDeployment({\n sk,\n allFiles,\n client,\n semaphore,\n owner,\n repo,\n resolvedSha,\n installRelDir,\n scopeRoot,\n sourceUrl,\n repository,\n provenanceRef,\n sourceKey,\n frozen,\n logger,\n });\n\n deployed.sort((a, b) =>\n a.relativeToScopeRoot < b.relativeToScopeRoot\n ? -1\n : a.relativeToScopeRoot > b.relativeToScopeRoot\n ? 1\n : 0,\n );\n const deployedFiles = deployed.map((d) => d.relativeToScopeRoot);\n const contentHash = computeContentHash(deployed);\n\n assertFrozenSkillIntegrity({\n frozen,\n locked,\n contentHash,\n sourceKey,\n skillName: sk.name,\n agent,\n scope,\n logger,\n });\n\n // Under --frozen we deliberately do NOT write here even after the\n // integrity check passes. Writes are deferred to the top-level installGh\n // so that a sibling source failing its check cannot leave partial bytes\n // on disk from a peer that already passed.\n const installation: GhLockInstallation = {\n source: sourceKey,\n owner,\n repo,\n agent,\n scope,\n skill: sk.name,\n resolved_ref: resolvedRef,\n resolved_commit: resolvedSha,\n install_dir: toPosixPath(installRelDir),\n deployed_files: deployedFiles,\n content_hash: contentHash,\n };\n if (rs.ref !== undefined) {\n installation.requested_ref = rs.ref;\n }\n results.push({ installation, deployed });\n\n logger.info(\n `Installed gh skill \"${sk.name}\" from ${sourceKey} (agent=${agent}, scope=${scope}, ref=${resolvedRef})`,\n );\n }\n\n return results;\n}\n\n/**\n * Resolve the ref for a gh source. Order: explicit `entry.ref`, then the latest\n * release's tag, then the default branch (when the repo has no releases).\n * Returns the resolved ref, its commit SHA, and whether a release tag was used.\n */\nasync function resolveGhRef(params: {\n rs: ResolvedSource;\n client: GitHubClient;\n owner: string;\n repo: string;\n sourceKey: string;\n logger: Logger;\n}): Promise<{ resolvedRef: string; resolvedSha: string; usedTag: boolean }> {\n const { rs, client, owner, repo, sourceKey, logger } = params;\n let resolvedRef: string;\n let usedTag = false;\n if (rs.ref) {\n resolvedRef = rs.ref;\n } else {\n try {\n const release = await client.getLatestRelease(owner, repo);\n resolvedRef = release.tag_name;\n usedTag = true;\n } catch (error) {\n // gh's behavior: when a repo has no releases, getLatestRelease returns\n // 404. We treat any 404 (real GitHubClientError or any thrown value\n // carrying statusCode 404) as \"no releases\" and fall back to the\n // default branch. Other errors propagate.\n if (is404(error)) {\n resolvedRef = await client.getDefaultBranch(owner, repo);\n } else {\n throw error;\n }\n }\n }\n const resolvedSha = await client.resolveRefToSha(owner, repo, resolvedRef);\n logger.debug(`Resolved ${sourceKey} -> ref=${resolvedRef} sha=${resolvedSha}`);\n return { resolvedRef, resolvedSha, usedTag };\n}\n\n/**\n * List `skills/` and validate which subdirectories are actual skills (contain a\n * SKILL.md). Returns null (with a warn log) when the `skills/` directory 404s so\n * the caller can skip the source. Validation is sequential to avoid hammering\n * the API for large monorepos beyond FETCH_CONCURRENCY_LIMIT.\n */\nasync function discoverValidatedSkills(params: {\n client: GitHubClient;\n semaphore: Semaphore;\n owner: string;\n repo: string;\n resolvedSha: string;\n sourceKey: string;\n logger: Logger;\n}): Promise<Array<{ name: string; path: string }> | null> {\n const { client, semaphore, owner, repo, resolvedSha, sourceKey, logger } = params;\n let topLevel: Awaited<ReturnType<GitHubClient[\"listDirectory\"]>>;\n try {\n topLevel = await client.listDirectory(owner, repo, SKILLS_REMOTE_DIR, resolvedSha);\n } catch (error) {\n if (is404(error)) {\n logger.warn(`No skills/ directory found in ${sourceKey}. Skipping.`);\n return null;\n }\n throw error;\n }\n\n const skillDirs = topLevel\n .filter((e) => e.type === \"dir\")\n .map((e) => ({ name: e.name, path: e.path }));\n\n const validatedSkills: Array<{ name: string; path: string }> = [];\n for (const sk of skillDirs) {\n const info = await withSemaphore(semaphore, () =>\n client.getFileInfo(owner, repo, posix.join(sk.path, SKILL_FILE_NAME), resolvedSha),\n );\n if (info) {\n validatedSkills.push(sk);\n }\n }\n return validatedSkills;\n}\n\n/**\n * Apply the explicit `entry.skills` filter to the validated skills, warning for\n * each requested name that is absent upstream. Returns all validated skills when\n * no filter is provided.\n */\nfunction selectSkills(params: {\n validatedSkills: Array<{ name: string; path: string }>;\n entry: SourceEntry;\n sourceKey: string;\n logger: Logger;\n}): Array<{ name: string; path: string }> {\n const { validatedSkills, entry, sourceKey, logger } = params;\n if (!entry.skills || entry.skills.length === 0) {\n return validatedSkills;\n }\n const requested = new Set(entry.skills);\n const selected = validatedSkills.filter((s) => requested.has(s.name));\n const presentNames = new Set(validatedSkills.map((s) => s.name));\n for (const want of entry.skills) {\n if (!presentNames.has(want)) {\n logger.warn(`Requested skill \"${want}\" not found in ${sourceKey} under skills/. Skipping.`);\n }\n }\n return selected;\n}\n\n/**\n * Frozen-mode per-skill coverage check. Throws when any selected skill has no\n * matching lock installation for the (source, agent, scope) tuple.\n */\nfunction assertFrozenSkillCoverage(params: {\n selected: Array<{ name: string; path: string }>;\n existingLock: GhLock;\n sourceKey: string;\n agent: GhAgent;\n scope: GhScope;\n}): void {\n const { selected, existingLock, sourceKey, agent, scope } = params;\n const missing: string[] = [];\n for (const sk of selected) {\n const locked = findGhLockInstallation(existingLock, {\n source: sourceKey,\n agent,\n scope,\n skill: sk.name,\n });\n if (!locked) {\n missing.push(sk.name);\n }\n }\n if (missing.length > 0) {\n throw new Error(\n `Frozen install failed: rulesync-gh.lock.yaml is missing entries for ${sourceKey} (agent=${agent}, scope=${scope}) skills: ${missing.join(\", \")}. Run 'rulesync install --mode gh' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Fetch, validate, and (under non-frozen) write a single skill's file tree,\n * returning the deployable files. Oversized or out-of-bounds files are skipped\n * with a warn log; SKILL.md files have provenance frontmatter injected.\n */\nasync function buildSkillDeployment(params: {\n sk: { name: string; path: string };\n allFiles: Awaited<ReturnType<typeof listDirectoryRecursive>>;\n client: GitHubClient;\n semaphore: Semaphore;\n owner: string;\n repo: string;\n resolvedSha: string;\n installRelDir: string;\n scopeRoot: string;\n sourceUrl: string;\n repository: string;\n provenanceRef: string;\n sourceKey: string;\n frozen: boolean;\n logger: Logger;\n}): Promise<DeployedFile[]> {\n const {\n sk,\n allFiles,\n client,\n semaphore,\n owner,\n repo,\n resolvedSha,\n installRelDir,\n scopeRoot,\n sourceUrl,\n repository,\n provenanceRef,\n sourceKey,\n frozen,\n logger,\n } = params;\n\n const deployed: DeployedFile[] = [];\n for (const file of allFiles) {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${sourceKey}: ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n // Path of the file relative to the skill directory root upstream.\n const relativeToSkill = posix.relative(sk.path, toPosixPath(file.path));\n if (!relativeToSkill || relativeToSkill.startsWith(\"..\") || posix.isAbsolute(relativeToSkill)) {\n logger.warn(`Skipping \"${file.path}\" from ${sourceKey}: resolved outside of \"${sk.path}\".`);\n continue;\n }\n\n // Path under the scope root (relative). This is the value persisted to\n // the lockfile.\n const deployRelative = toPosixPath(join(installRelDir, sk.name, relativeToSkill));\n // Path-traversal hardening rooted at the scope root, then a tighter\n // check rooted at the per-(agent,scope) install dir to refuse anything\n // that escapes the agent-specific deployment directory.\n checkPathTraversal({ relativePath: deployRelative, intendedRootDir: scopeRoot });\n const installAbs = join(scopeRoot, installRelDir);\n const withinInstallDir = toPosixPath(join(sk.name, relativeToSkill));\n checkPathTraversal({ relativePath: withinInstallDir, intendedRootDir: installAbs });\n\n let content = await withSemaphore(semaphore, () =>\n client.getFileContent(owner, repo, file.path, resolvedSha),\n );\n const byteLength = Buffer.byteLength(content, \"utf8\");\n if (byteLength > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${sourceKey}: fetched ${(byteLength / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n\n // Inject provenance frontmatter into SKILL.md files. Other files\n // (e.g. supporting markdown, scripts) pass through unchanged.\n if (basename(file.path) === SKILL_FILE_NAME) {\n try {\n content = injectSourceMetadata({\n content,\n source: sourceUrl,\n repository,\n ref: provenanceRef,\n });\n } catch {\n // Frontmatter exists but is not parseable. Fall back to a fresh\n // prepend so we still record provenance — but warn the user.\n logger.warn(\n `Frontmatter in ${file.path} (${sourceKey}) is invalid. Prepending a fresh provenance block.`,\n );\n content = `---\\nsource: ${sourceUrl}\\nrepository: ${repository}\\nref: ${provenanceRef}\\n---\\n${content}`;\n }\n }\n\n const absolutePath = join(scopeRoot, deployRelative);\n deployed.push({ relativeToScopeRoot: deployRelative, absolutePath, content });\n\n if (!frozen) {\n await writeFileContent(absolutePath, content);\n }\n }\n return deployed;\n}\n\n/**\n * Frozen integrity check: refuse to overwrite known-good bytes with tampered\n * ones when the prior content_hash matches the rulesync format. Hashes not\n * written by rulesync are skipped (debug-logged), preserving the commit-SHA pin.\n */\nfunction assertFrozenSkillIntegrity(params: {\n frozen: boolean;\n locked: GhLockInstallation | undefined;\n contentHash: string;\n sourceKey: string;\n skillName: string;\n agent: GhAgent;\n scope: GhScope;\n logger: Logger;\n}): void {\n const { frozen, locked, contentHash, sourceKey, skillName, agent, scope, logger } = params;\n if (frozen && locked?.content_hash) {\n if (RULESYNC_CONTENT_HASH_REGEX.test(locked.content_hash)) {\n if (locked.content_hash !== contentHash) {\n throw new Error(\n `content_hash mismatch for ${sourceKey} skill \"${skillName}\" (agent=${agent}, scope=${scope}): lock=${locked.content_hash} computed=${contentHash}. Refuse to trust the deployment under --frozen.`,\n );\n }\n } else {\n logger.debug(\n `Skipping content_hash integrity check for ${sourceKey} skill \"${skillName}\": recorded hash \"${locked.content_hash}\" was not written by rulesync.`,\n );\n }\n }\n}\n\nasync function removeStaleFile(params: {\n relativePath: string;\n scope: GhScope;\n projectRoot: string;\n logger: Logger;\n}): Promise<void> {\n const { relativePath, scope, projectRoot, logger } = params;\n if (posix.isAbsolute(relativePath) || relativePath.split(/[/\\\\]/).includes(\"..\")) {\n logger.warn(`Refusing to remove stale gh file with suspicious path: \"${relativePath}\".`);\n return;\n }\n const scopeRoot = scope === \"user\" ? getHomeDirectory() : projectRoot;\n try {\n checkPathTraversal({ relativePath, intendedRootDir: scopeRoot });\n } catch {\n logger.warn(`Refusing to remove stale gh file outside ${scope} root: \"${relativePath}\".`);\n return;\n }\n const absolute = join(scopeRoot, relativePath);\n await removeFile(absolute);\n logger.debug(`Removed stale gh file: ${relativePath}`);\n}\n\n/**\n * Detect a 404-like error in a way that tolerates both real `GitHubClientError`\n * instances and any other thrown value that exposes a numeric `statusCode`\n * (e.g. plain Errors raised from a test mock that does not import the real\n * client class).\n */\nfunction is404(error: unknown): boolean {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return true;\n }\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"statusCode\" in error &&\n error.statusCode === 404\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * SHA-256 over a canonical, order-independent representation of the deployed\n * files. Identical algorithm to the apm-install hash so users familiar with\n * one mode can read the other.\n */\nfunction computeContentHash(\n files: Array<{ relativeToScopeRoot: string; content: string }>,\n): string {\n const hash = createHash(\"sha256\");\n for (const { relativeToScopeRoot, content } of files) {\n hash.update(relativeToScopeRoot);\n hash.update(\"\\0\");\n hash.update(content);\n hash.update(\"\\0\");\n }\n return `sha256:${hash.digest(\"hex\")}`;\n}\n","import { execFile } from \"node:child_process\";\nimport { isAbsolute, join, posix, relative } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport { MAX_FILE_SIZE } from \"../constants/rulesync-paths.js\";\nimport {\n createTempDirectory,\n directoryExists,\n getFileSize,\n isSymlink,\n listDirectoryFiles,\n readFileContent,\n removeTempDirectory,\n} from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { findControlCharacter } from \"../utils/validation.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Timeout for all git CLI operations (60 seconds). */\nconst GIT_TIMEOUT_MS = 60_000;\n\nconst ALLOWED_URL_SCHEMES =\n /^(https?:\\/\\/|ssh:\\/\\/|git:\\/\\/|file:\\/\\/\\/).+$|^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9.-]+:[a-zA-Z0-9_.+/~-]+$/;\n\nconst INSECURE_URL_SCHEMES = /^(git:\\/\\/|http:\\/\\/)/;\n\nexport class GitClientError extends Error {\n constructor(message: string, cause?: unknown) {\n super(message, { cause });\n this.name = \"GitClientError\";\n }\n}\n\nexport function validateGitUrl(url: string, options?: { logger?: Logger }): void {\n const ctrl = findControlCharacter(url);\n if (ctrl) {\n throw new GitClientError(\n `Git URL contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n if (!ALLOWED_URL_SCHEMES.test(url)) {\n throw new GitClientError(\n `Unsupported or unsafe git URL: \"${url}\". Use https, ssh, git, or file schemes.`,\n );\n }\n if (INSECURE_URL_SCHEMES.test(url)) {\n options?.logger?.warn(\n `URL \"${url}\" uses an unencrypted protocol. Consider using https:// or ssh:// instead.`,\n );\n }\n}\n\n/**\n * Validate a ref string before passing to git commands.\n * Rejects refs that start with \"-\" or contain control characters.\n */\nexport function validateRef(ref: string): void {\n if (ref.startsWith(\"-\")) {\n throw new GitClientError(`Ref must not start with \"-\": \"${ref}\"`);\n }\n const ctrl = findControlCharacter(ref);\n if (ctrl) {\n throw new GitClientError(\n `Ref contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n}\n\nlet gitChecked = false;\n\nexport async function checkGitAvailable(): Promise<void> {\n if (gitChecked) return;\n try {\n await execFileAsync(\"git\", [\"--version\"], { timeout: GIT_TIMEOUT_MS });\n gitChecked = true;\n } catch {\n throw new GitClientError(\"git is not installed or not found in PATH\");\n }\n}\n\n/** Reset the cached git availability check (for testing). */\nexport function resetGitCheck(): void {\n gitChecked = false;\n}\n\nexport async function resolveDefaultRef(url: string): Promise<{ ref: string; sha: string }> {\n validateGitUrl(url);\n await checkGitAvailable();\n try {\n const { stdout } = await execFileAsync(\"git\", [\"ls-remote\", \"--symref\", \"--\", url, \"HEAD\"], {\n timeout: GIT_TIMEOUT_MS,\n });\n const ref = stdout.match(/^ref: refs\\/heads\\/(.+)\\tHEAD$/m)?.[1];\n const sha = stdout.match(/^([0-9a-f]{40})\\tHEAD$/m)?.[1];\n if (!ref || !sha) throw new GitClientError(`Could not parse default branch from: ${url}`);\n validateRef(ref);\n return { ref, sha };\n } catch (error) {\n if (error instanceof GitClientError) throw error;\n throw new GitClientError(`Failed to resolve default ref for ${url}`, error);\n }\n}\n\nexport async function resolveRefToSha(url: string, ref: string): Promise<string> {\n validateGitUrl(url);\n validateRef(ref);\n await checkGitAvailable();\n try {\n const { stdout } = await execFileAsync(\"git\", [\"ls-remote\", \"--\", url, ref], {\n timeout: GIT_TIMEOUT_MS,\n });\n const sha = stdout.match(/^([0-9a-f]{40})\\t/m)?.[1];\n if (!sha) throw new GitClientError(`Ref \"${ref}\" not found in ${url}`);\n return sha;\n } catch (error) {\n if (error instanceof GitClientError) throw error;\n throw new GitClientError(`Failed to resolve ref \"${ref}\" for ${url}`, error);\n }\n}\n\n/**\n * Clone a repo at the given ref and return all files under skillsPath.\n * The `ref` must be a branch or tag name (not a commit SHA) because\n * `git clone --branch` does not accept raw SHAs.\n */\nexport async function fetchSkillFiles(params: {\n url: string;\n ref: string;\n skillsPath: string;\n logger?: Logger;\n}): Promise<Array<{ relativePath: string; content: string; size: number }>> {\n const { url, ref, skillsPath, logger } = params;\n validateGitUrl(url, { logger });\n validateRef(ref);\n if (skillsPath.split(/[/\\\\]/).includes(\"..\") || isAbsolute(skillsPath)) {\n throw new GitClientError(\n `Invalid skillsPath \"${skillsPath}\": must be a relative path without \"..\"`,\n );\n }\n const ctrl = findControlCharacter(skillsPath);\n if (ctrl) {\n throw new GitClientError(\n `skillsPath contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n await checkGitAvailable();\n const tmpDir = await createTempDirectory(\"rulesync-git-\");\n // Treat empty/\".\" paths as the repository root. Cone-mode sparse-checkout\n // with such patterns only restores the top-level files (it intentionally\n // excludes any subdirectory), so we must check out the entire working tree\n // instead. Otherwise repositories whose skills live directly at the root\n // (e.g. `<repo>/<skill-name>/SKILL.md` without a `skills/` container)\n // would only yield root-level files like README.md.\n // Normalize first so variants like \"./.\", \".//\", or Windows \".\\\\\" are also\n // recognized as the root and don't fall back to the (buggy) sparse-checkout path.\n const normalizedSkillsPath = posix.normalize(skillsPath.replace(/\\\\/g, \"/\")).replace(/\\/+$/, \"\");\n const isRootPath = normalizedSkillsPath === \"\" || normalizedSkillsPath === \".\";\n try {\n await execFileAsync(\n \"git\",\n [\n \"clone\",\n \"--depth\",\n \"1\",\n \"--branch\",\n ref,\n \"--no-checkout\",\n \"--filter=blob:none\",\n \"--\",\n url,\n tmpDir,\n ],\n { timeout: GIT_TIMEOUT_MS },\n );\n if (isRootPath) {\n // Disable sparse-checkout and restore the full tree.\n await execFileAsync(\"git\", [\"-C\", tmpDir, \"sparse-checkout\", \"disable\"], {\n timeout: GIT_TIMEOUT_MS,\n });\n } else {\n await execFileAsync(\"git\", [\"-C\", tmpDir, \"sparse-checkout\", \"set\", \"--\", skillsPath], {\n timeout: GIT_TIMEOUT_MS,\n });\n }\n await execFileAsync(\"git\", [\"-C\", tmpDir, \"checkout\"], { timeout: GIT_TIMEOUT_MS });\n const skillsDir = isRootPath ? tmpDir : join(tmpDir, skillsPath);\n if (!(await directoryExists(skillsDir))) return [];\n return await walkDirectory(skillsDir, skillsDir, 0, { totalFiles: 0, totalSize: 0 }, logger);\n } catch (error) {\n if (error instanceof GitClientError) throw error;\n throw new GitClientError(`Failed to fetch skill files from ${url}`, error);\n } finally {\n await removeTempDirectory(tmpDir);\n }\n}\n\nconst MAX_WALK_DEPTH = 20;\nconst MAX_TOTAL_FILES = 10_000;\nconst MAX_TOTAL_SIZE = 100 * 1024 * 1024; // 100 MB\n\n/** Mutable context for tracking totals across recursive walkDirectory calls. */\ntype WalkContext = { totalFiles: number; totalSize: number };\n\nasync function walkDirectory(\n dir: string,\n outputRoot: string,\n depth: number = 0,\n ctx: WalkContext = { totalFiles: 0, totalSize: 0 },\n logger?: Logger,\n): Promise<Array<{ relativePath: string; content: string; size: number }>> {\n if (depth > MAX_WALK_DEPTH) {\n throw new GitClientError(\n `Directory tree exceeds max depth of ${MAX_WALK_DEPTH}: \"${dir}\". Aborting to prevent resource exhaustion.`,\n );\n }\n const results: Array<{ relativePath: string; content: string; size: number }> = [];\n for (const name of await listDirectoryFiles(dir)) {\n if (name === \".git\") continue;\n const fullPath = join(dir, name);\n if (await isSymlink(fullPath)) {\n logger?.warn(`Skipping symlink \"${fullPath}\".`);\n continue;\n }\n if (await directoryExists(fullPath)) {\n results.push(...(await walkDirectory(fullPath, outputRoot, depth + 1, ctx, logger)));\n } else {\n const size = await getFileSize(fullPath);\n if (size > MAX_FILE_SIZE) {\n logger?.warn(\n `Skipping file \"${fullPath}\" (${(size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n continue;\n }\n ctx.totalFiles++;\n ctx.totalSize += size;\n if (ctx.totalFiles >= MAX_TOTAL_FILES) {\n throw new GitClientError(\n `Repository exceeds max file count of ${MAX_TOTAL_FILES}. Aborting to prevent resource exhaustion.`,\n );\n }\n if (ctx.totalSize >= MAX_TOTAL_SIZE) {\n throw new GitClientError(\n `Repository exceeds max total size of ${MAX_TOTAL_SIZE / 1024 / 1024}MB. Aborting to prevent resource exhaustion.`,\n );\n }\n const content = await readFileContent(fullPath);\n results.push({ relativePath: relative(outputRoot, fullPath), content, size });\n }\n }\n return results;\n}\n","import { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\n\nimport { optional, refine, z } from \"zod/mini\";\n\nimport { RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { fileExists, readFileContent, writeFileContent } from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/** Current lockfile format version. Bump when the schema changes. */\nexport const LOCKFILE_VERSION = 1;\n\n/**\n * Schema for a single locked skill entry with content integrity.\n */\nconst LockedSkillSchema = z.object({\n integrity: z.string(),\n});\nexport type LockedSkill = z.infer<typeof LockedSkillSchema>;\n\n/**\n * Schema for a single locked source entry.\n */\nconst LockedSourceSchema = z.object({\n requestedRef: optional(z.string()),\n resolvedRef: z\n .string()\n .check(refine((v) => /^[0-9a-f]{40}$/.test(v), \"resolvedRef must be a 40-character hex SHA\")),\n resolvedAt: optional(z.string()),\n skills: z.record(z.string(), LockedSkillSchema),\n});\nexport type LockedSource = z.infer<typeof LockedSourceSchema>;\n\n/**\n * Schema for the full lockfile (current version).\n */\nconst SourcesLockSchema = z.object({\n lockfileVersion: z.number(),\n sources: z.record(z.string(), LockedSourceSchema),\n});\nexport type SourcesLock = z.infer<typeof SourcesLockSchema>;\n\n/**\n * Schema for the legacy v0 lockfile format (skills as string array, no version field).\n */\nconst LegacyLockedSourceSchema = z.object({\n resolvedRef: z.string(),\n skills: z.array(z.string()),\n});\n\nconst LegacySourcesLockSchema = z.object({\n sources: z.record(z.string(), LegacyLockedSourceSchema),\n});\n\n/**\n * Migrate a legacy lockfile (string[] skills, no version) to the current format.\n * Skills get empty integrity since we can't compute it retroactively.\n */\nfunction migrateLegacyLock(params: {\n legacy: z.infer<typeof LegacySourcesLockSchema>;\n logger: Logger;\n}): SourcesLock {\n const { legacy, logger } = params;\n const sources: Record<string, LockedSource> = {};\n for (const [key, entry] of Object.entries(legacy.sources)) {\n const skills: Record<string, LockedSkill> = {};\n for (const name of entry.skills) {\n skills[name] = { integrity: \"\" };\n }\n sources[key] = {\n resolvedRef: entry.resolvedRef,\n skills,\n };\n }\n logger.info(\n \"Migrated legacy sources lockfile to version 1. Run 'rulesync install --update' to populate integrity hashes.\",\n );\n return { lockfileVersion: LOCKFILE_VERSION, sources };\n}\n\n/**\n * Create an empty lockfile structure.\n */\nexport function createEmptyLock(): SourcesLock {\n return { lockfileVersion: LOCKFILE_VERSION, sources: {} };\n}\n\n/**\n * Read the lockfile from disk.\n * @returns The parsed lockfile, or an empty lockfile if it doesn't exist or is invalid.\n */\nexport async function readLockFile(params: {\n projectRoot: string;\n logger: Logger;\n}): Promise<SourcesLock> {\n const { logger } = params;\n const lockPath = join(params.projectRoot, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);\n\n if (!(await fileExists(lockPath))) {\n logger.debug(\"No sources lockfile found, starting fresh.\");\n return createEmptyLock();\n }\n\n try {\n const content = await readFileContent(lockPath);\n const data = JSON.parse(content);\n\n // Try current schema first\n const result = SourcesLockSchema.safeParse(data);\n if (result.success) {\n return result.data;\n }\n\n // Try legacy schema (no lockfileVersion, skills as string[])\n const legacyResult = LegacySourcesLockSchema.safeParse(data);\n if (legacyResult.success) {\n return migrateLegacyLock({ legacy: legacyResult.data, logger });\n }\n\n logger.warn(\n `Invalid sources lockfile format (${RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`,\n );\n return createEmptyLock();\n } catch {\n logger.warn(\n `Failed to read sources lockfile (${RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`,\n );\n return createEmptyLock();\n }\n}\n\n/**\n * Write the lockfile to disk.\n */\nexport async function writeLockFile(params: {\n projectRoot: string;\n lock: SourcesLock;\n logger: Logger;\n}): Promise<void> {\n const { logger } = params;\n const lockPath = join(params.projectRoot, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);\n const content = JSON.stringify(params.lock, null, 2) + \"\\n\";\n await writeFileContent(lockPath, content);\n logger.debug(`Wrote sources lockfile to ${lockPath}`);\n}\n\n/**\n * Compute a SHA-256 integrity hash for a skill's contents.\n * Takes a sorted list of [relativePath, content] pairs to produce a deterministic hash.\n */\nexport function computeSkillIntegrity(files: Array<{ path: string; content: string }>): string {\n const hash = createHash(\"sha256\");\n // Sort by path for deterministic ordering\n const sorted = files.toSorted((a, b) => a.path.localeCompare(b.path));\n for (const file of sorted) {\n hash.update(file.path);\n hash.update(\"\\0\");\n hash.update(file.content);\n hash.update(\"\\0\");\n }\n return `sha256-${hash.digest(\"hex\")}`;\n}\n\n/**\n * Normalize a source key for consistent lockfile lookups.\n * Strips URL prefixes, provider prefixes, trailing slashes, .git suffix, and lowercases.\n */\nexport function normalizeSourceKey(source: string): string {\n let key = source;\n\n // Strip common URL prefixes\n for (const prefix of [\n \"https://www.github.com/\",\n \"https://github.com/\",\n \"http://www.github.com/\",\n \"http://github.com/\",\n \"https://www.gitlab.com/\",\n \"https://gitlab.com/\",\n \"http://www.gitlab.com/\",\n \"http://gitlab.com/\",\n ]) {\n if (key.toLowerCase().startsWith(prefix)) {\n key = key.substring(prefix.length);\n break;\n }\n }\n\n // Strip provider prefix\n for (const provider of [\"github:\", \"gitlab:\"]) {\n if (key.startsWith(provider)) {\n key = key.substring(provider.length);\n break;\n }\n }\n\n // Remove trailing slashes\n key = key.replace(/\\/+$/, \"\");\n\n // Remove .git suffix from repo\n key = key.replace(/\\.git$/, \"\");\n\n // Lowercase for case-insensitive matching\n key = key.toLowerCase();\n\n return key;\n}\n\n/**\n * Get the locked entry for a source key, if it exists.\n */\nexport function getLockedSource(lock: SourcesLock, sourceKey: string): LockedSource | undefined {\n const normalized = normalizeSourceKey(sourceKey);\n // Look up by normalized key\n for (const [key, value] of Object.entries(lock.sources)) {\n if (normalizeSourceKey(key) === normalized) {\n return value;\n }\n }\n return undefined;\n}\n\n/**\n * Set (or update) a locked entry for a source key.\n */\nexport function setLockedSource(\n lock: SourcesLock,\n sourceKey: string,\n entry: LockedSource,\n): SourcesLock {\n const normalized = normalizeSourceKey(sourceKey);\n // Remove any existing entries with the same normalized key\n const filteredSources: Record<string, LockedSource> = {};\n for (const [key, value] of Object.entries(lock.sources)) {\n if (normalizeSourceKey(key) !== normalized) {\n filteredSources[key] = value;\n }\n }\n return {\n lockfileVersion: lock.lockfileVersion,\n sources: {\n ...filteredSources,\n [normalized]: entry,\n },\n };\n}\n\n/**\n * Get the skill names from a locked source entry.\n */\nexport function getLockedSkillNames(entry: LockedSource): string[] {\n return Object.keys(entry.skills);\n}\n","import { join, resolve, sep } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport type { SourceEntry } from \"../config/config.js\";\nimport { SKILL_FILE_NAME } from \"../constants/general.js\";\nimport {\n FETCH_CONCURRENCY_LIMIT,\n MAX_FILE_SIZE,\n RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH,\n} from \"../constants/rulesync-paths.js\";\nimport { getLocalSkillDirNames } from \"../features/skills/skills-utils.js\";\nimport type { GitHubFileEntry, ParsedSource } from \"../types/fetch.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n directoryExists,\n removeDirectory,\n writeFileContent,\n} from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport {\n GitClientError,\n fetchSkillFiles,\n resolveDefaultRef,\n resolveRefToSha,\n validateRef,\n} from \"./git-client.js\";\nimport { GitHubClient, GitHubClientError, logGitHubAuthHints } from \"./github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"./github-utils.js\";\nimport { parseSource } from \"./source-parser.js\";\nimport {\n type LockedSkill,\n type LockedSource,\n type SourcesLock,\n computeSkillIntegrity,\n createEmptyLock,\n getLockedSkillNames,\n getLockedSource,\n normalizeSourceKey,\n readLockFile,\n setLockedSource,\n writeLockFile,\n} from \"./sources-lock.js\";\n\nexport type ResolveAndFetchSourcesOptions = {\n /** Force re-resolve all refs, ignoring the lockfile. */\n updateSources?: boolean;\n /** Skip fetching entirely (use what's already on disk). */\n skipSources?: boolean;\n /** Fail if lockfile is missing or doesn't match sources (for CI). */\n frozen?: boolean;\n /** GitHub token for private repositories. */\n token?: string;\n};\n\nexport type ResolveAndFetchSourcesResult = {\n fetchedSkillCount: number;\n sourcesProcessed: number;\n};\n\ntype RemoteSkillFile = {\n relativePath: string;\n content: string;\n};\n\n/**\n * Resolve declared sources, fetch remote skills into .rulesync/skills/.curated/,\n * and update the lockfile.\n */\nexport async function resolveAndFetchSources(params: {\n sources: SourceEntry[];\n projectRoot: string;\n options?: ResolveAndFetchSourcesOptions;\n logger: Logger;\n}): Promise<ResolveAndFetchSourcesResult> {\n const { sources, projectRoot, options = {}, logger } = params;\n\n if (sources.length === 0) {\n return { fetchedSkillCount: 0, sourcesProcessed: 0 };\n }\n\n if (options.skipSources) {\n logger.info(\"Skipping source fetching.\");\n return { fetchedSkillCount: 0, sourcesProcessed: 0 };\n }\n\n // Read existing lockfile\n let lock: SourcesLock = options.updateSources\n ? createEmptyLock()\n : await readLockFile({ projectRoot, logger });\n\n // Frozen mode: validate lockfile covers all declared sources.\n // Missing curated skills are fetched using locked refs.\n if (options.frozen) {\n assertFrozenLockCoversSources({ lock, sources });\n }\n\n const originalLockJson = JSON.stringify(lock);\n\n // Resolve GitHub token\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n\n // Determine local skills (in .rulesync/skills/ but not in .curated/)\n const localSkillNames = await getLocalSkillDirNames(projectRoot);\n\n let totalSkillCount = 0;\n const allFetchedSkillNames = new Set<string>();\n\n for (const sourceEntry of sources) {\n try {\n const result = await fetchSourceByTransport({\n sourceEntry,\n client,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames: allFetchedSkillNames,\n updateSources: options.updateSources ?? false,\n frozen: options.frozen ?? false,\n logger,\n });\n const { skillCount, fetchedSkillNames, updatedLock } = result;\n\n lock = updatedLock;\n totalSkillCount += skillCount;\n for (const name of fetchedSkillNames) {\n allFetchedSkillNames.add(name);\n }\n } catch (error) {\n logger.error(`Failed to fetch source \"${sourceEntry.source}\": ${formatError(error)}`);\n if (error instanceof GitHubClientError) {\n logGitHubAuthHints({ error, logger });\n } else if (error instanceof GitClientError) {\n logGitClientHints({ error, logger });\n }\n }\n }\n\n lock = pruneStaleLockEntries({ lock, sources, logger });\n\n // Only write lockfile if it has changed (and not in frozen mode)\n if (!options.frozen && JSON.stringify(lock) !== originalLockJson) {\n await writeLockFile({ projectRoot, lock, logger });\n } else {\n logger.debug(\"Lockfile unchanged, skipping write.\");\n }\n\n return { fetchedSkillCount: totalSkillCount, sourcesProcessed: sources.length };\n}\n\n/**\n * Log contextual hints for GitClientError to help users troubleshoot.\n */\nfunction logGitClientHints(params: { error: GitClientError; logger: Logger }): void {\n const { error, logger } = params;\n if (error.message.includes(\"not installed\")) {\n logger.info(\"Hint: Install git and ensure it is available on your PATH.\");\n } else {\n logger.info(\"Hint: Check your git credentials (SSH keys, credential helper, or access token).\");\n }\n}\n\n/**\n * Frozen mode: validate the lockfile covers every declared source. Throws with\n * remediation guidance listing any uncovered source keys.\n */\nfunction assertFrozenLockCoversSources(params: {\n lock: SourcesLock;\n sources: SourceEntry[];\n}): void {\n const { lock, sources } = params;\n const missingKeys: string[] = [];\n\n for (const source of sources) {\n const locked = getLockedSource(lock, source.source);\n if (!locked) {\n missingKeys.push(source.source);\n }\n }\n if (missingKeys.length > 0) {\n throw new Error(\n `Frozen install failed: lockfile is missing entries for: ${missingKeys.join(\", \")}. Run 'rulesync install' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Dispatch a single source to the transport-specific fetcher (git CLI vs.\n * GitHub REST API), preserving the original default of \"github\".\n */\nasync function fetchSourceByTransport(params: {\n sourceEntry: SourceEntry;\n client: GitHubClient;\n projectRoot: string;\n lock: SourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n frozen: boolean;\n logger: Logger;\n}): Promise<{ skillCount: number; fetchedSkillNames: string[]; updatedLock: SourcesLock }> {\n const {\n sourceEntry,\n client,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n frozen,\n logger,\n } = params;\n const transport = sourceEntry.transport ?? \"github\";\n if (transport === \"git\") {\n return fetchSourceViaGit({\n sourceEntry,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n frozen,\n logger,\n });\n }\n return fetchSource({\n sourceEntry,\n client,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n logger,\n });\n}\n\n/**\n * Prune stale lockfile entries whose keys are not in the current sources\n * (immutable — returns a fresh lock object).\n */\nfunction pruneStaleLockEntries(params: {\n lock: SourcesLock;\n sources: SourceEntry[];\n logger: Logger;\n}): SourcesLock {\n const { lock, sources, logger } = params;\n const sourceKeys = new Set(sources.map((s) => normalizeSourceKey(s.source)));\n const prunedSources: typeof lock.sources = {};\n for (const [key, value] of Object.entries(lock.sources)) {\n if (sourceKeys.has(normalizeSourceKey(key))) {\n prunedSources[key] = value;\n } else {\n logger.debug(`Pruned stale lockfile entry: ${key}`);\n }\n }\n return { lockfileVersion: lock.lockfileVersion, sources: prunedSources };\n}\n\n/**\n * Check if all locked skills exist on disk in the curated directory.\n */\nasync function checkLockedSkillsExist(curatedDir: string, skillNames: string[]): Promise<boolean> {\n if (skillNames.length === 0) return true;\n for (const name of skillNames) {\n if (!(await directoryExists(join(curatedDir, name)))) {\n return false;\n }\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers for fetchSource and fetchSourceViaGit\n// ---------------------------------------------------------------------------\n\n/**\n * Remove previously curated skill directories for a source before re-fetching.\n * Validates that each path resolves within the curated directory to prevent traversal.\n */\nasync function cleanPreviousCuratedSkills(params: {\n curatedDir: string;\n lockedSkillNames: string[];\n logger: Logger;\n}): Promise<void> {\n const { curatedDir, lockedSkillNames, logger } = params;\n const resolvedCuratedDir = resolve(curatedDir);\n for (const prevSkill of lockedSkillNames) {\n const prevDir = join(curatedDir, prevSkill);\n if (!resolve(prevDir).startsWith(resolvedCuratedDir + sep)) {\n logger.warn(\n `Skipping removal of \"${prevSkill}\": resolved path is outside the curated directory.`,\n );\n continue;\n }\n if (await directoryExists(prevDir)) {\n await removeDirectory(prevDir);\n }\n }\n}\n\n/**\n * Check whether a skill should be skipped during fetching.\n * Returns true (with appropriate logging) if the skill should be skipped.\n */\nfunction shouldSkipSkill(params: {\n skillName: string;\n sourceKey: string;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n logger: Logger;\n}): boolean {\n const { skillName, sourceKey, localSkillNames, alreadyFetchedSkillNames, logger } = params;\n if (skillName.includes(\"..\") || skillName.includes(\"/\") || skillName.includes(\"\\\\\")) {\n logger.warn(\n `Skipping skill with invalid name \"${skillName}\" from ${sourceKey}: contains path traversal characters.`,\n );\n return true;\n }\n if (localSkillNames.has(skillName)) {\n logger.debug(\n `Skipping remote skill \"${skillName}\" from ${sourceKey}: local skill takes precedence.`,\n );\n return true;\n }\n if (alreadyFetchedSkillNames.has(skillName)) {\n logger.warn(\n `Skipping duplicate skill \"${skillName}\" from ${sourceKey}: already fetched from another source.`,\n );\n return true;\n }\n return false;\n}\n\n/**\n * Write skill files to disk, compute integrity, and check against the lockfile.\n * Returns the computed LockedSkill entry.\n */\nasync function writeSkillAndComputeIntegrity(params: {\n skillName: string;\n files: Array<{ relativePath: string; content: string }>;\n curatedDir: string;\n locked: LockedSource | undefined;\n resolvedSha: string;\n sourceKey: string;\n logger: Logger;\n}): Promise<LockedSkill> {\n const { skillName, files, curatedDir, locked, resolvedSha, sourceKey, logger } = params;\n const written: Array<{ path: string; content: string }> = [];\n\n for (const file of files) {\n checkPathTraversal({\n relativePath: file.relativePath,\n intendedRootDir: join(curatedDir, skillName),\n });\n await writeFileContent(join(curatedDir, skillName, file.relativePath), file.content);\n written.push({ path: file.relativePath, content: file.content });\n }\n\n const integrity = computeSkillIntegrity(written);\n const lockedSkillEntry = locked?.skills[skillName];\n if (\n lockedSkillEntry?.integrity &&\n lockedSkillEntry.integrity !== integrity &&\n resolvedSha === locked?.resolvedRef\n ) {\n logger.warn(\n `Integrity mismatch for skill \"${skillName}\" from ${sourceKey}: expected \"${lockedSkillEntry.integrity}\", got \"${integrity}\". Content may have been tampered with.`,\n );\n }\n\n return { integrity };\n}\n\n/**\n * Merge newly fetched skills with existing locked skills and update the lockfile.\n */\nfunction buildLockUpdate(params: {\n lock: SourcesLock;\n sourceKey: string;\n fetchedSkills: Record<string, LockedSkill>;\n locked: LockedSource | undefined;\n requestedRef: string | undefined;\n resolvedSha: string;\n remoteSkillNames: string[];\n logger: Logger;\n}): { updatedLock: SourcesLock; fetchedNames: string[] } {\n const {\n lock,\n sourceKey,\n fetchedSkills,\n locked,\n requestedRef,\n resolvedSha,\n remoteSkillNames,\n logger,\n } = params;\n const fetchedNames = Object.keys(fetchedSkills);\n\n // Merge back locked skills that still exist in the remote but were skipped\n // (due to local precedence, already-fetched, etc.). Skills no longer present\n // in the remote (e.g. renamed or deleted upstream) are intentionally dropped.\n const remoteSet = new Set(remoteSkillNames);\n const mergedSkills: Record<string, LockedSkill> = { ...fetchedSkills };\n if (locked) {\n for (const [skillName, skillEntry] of Object.entries(locked.skills)) {\n if (!(skillName in mergedSkills) && remoteSet.has(skillName)) {\n mergedSkills[skillName] = skillEntry;\n }\n }\n }\n\n const updatedLock = setLockedSource(lock, sourceKey, {\n requestedRef,\n resolvedRef: resolvedSha,\n resolvedAt: new Date().toISOString(),\n skills: mergedSkills,\n });\n\n logger.info(\n `Fetched ${fetchedNames.length} skill(s) from ${sourceKey}: ${fetchedNames.join(\", \") || \"(none)\"}`,\n );\n\n return { updatedLock, fetchedNames };\n}\n\nfunction getFirstPathSeparatorIndex(path: string): number {\n const slashIndex = path.indexOf(\"/\");\n const backslashIndex = path.indexOf(\"\\\\\");\n if (slashIndex === -1) return backslashIndex;\n if (backslashIndex === -1) return slashIndex;\n return Math.min(slashIndex, backslashIndex);\n}\n\n/**\n * Decide whether a repository's root-level files should be installed as the\n * single requested skill (the \"root fallback\").\n *\n * A root fallback fires only when a single, non-wildcard skill was requested,\n * that skill's own directory is absent, and the repository root actually carries\n * a `SKILL.md`. Both the git transport (`groupRemoteFilesBySkillRoot`) and the\n * GitHub transport (`discoverGithubSkillDirs`) gate on these same conditions, so\n * the decision lives here to keep the two paths from drifting.\n */\nfunction shouldUseRootFallback(params: {\n skillFilter: string[];\n isWildcard: boolean;\n hasRootSkillFile: boolean;\n hasRequestedSkillDir: boolean;\n}): boolean {\n const { skillFilter, isWildcard, hasRootSkillFile, hasRequestedSkillDir } = params;\n const [singleSkillName] = skillFilter;\n return (\n !isWildcard &&\n skillFilter.length === 1 &&\n singleSkillName !== undefined &&\n hasRootSkillFile &&\n !hasRequestedSkillDir\n );\n}\n\nfunction groupRemoteFilesBySkillRoot(params: {\n remoteFiles: RemoteSkillFile[];\n skillFilter: string[];\n isWildcard: boolean;\n}): Map<string, RemoteSkillFile[]> {\n const { remoteFiles, skillFilter, isWildcard } = params;\n const grouped = new Map<string, RemoteSkillFile[]>();\n const rootLevelFiles: RemoteSkillFile[] = [];\n\n for (const file of remoteFiles) {\n const separatorIndex = getFirstPathSeparatorIndex(file.relativePath);\n if (separatorIndex === -1) {\n rootLevelFiles.push(file);\n continue;\n }\n\n const skillName = file.relativePath.substring(0, separatorIndex);\n if (skillName.length === 0) {\n continue;\n }\n\n const innerPath = file.relativePath.substring(separatorIndex + 1);\n const groupedFiles = grouped.get(skillName) ?? [];\n groupedFiles.push({ relativePath: innerPath, content: file.content });\n grouped.set(skillName, groupedFiles);\n }\n\n const [singleSkillName] = skillFilter;\n const hasRootSkillFile = rootLevelFiles.some((file) => file.relativePath === SKILL_FILE_NAME);\n if (\n singleSkillName !== undefined &&\n shouldUseRootFallback({\n skillFilter,\n isWildcard,\n hasRootSkillFile,\n hasRequestedSkillDir: grouped.has(singleSkillName),\n })\n ) {\n grouped.set(singleSkillName, rootLevelFiles);\n }\n\n return grouped;\n}\n\n// ---------------------------------------------------------------------------\n// Transport-specific fetch functions\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a GitHub source's ref to a commit SHA, preferring the locked SHA for\n * deterministic fetches and otherwise resolving the declared ref or default\n * branch. Returns the on-disk `ref` (SHA when freshly resolved, else locked\n * ref), the resolved SHA, and the requested ref.\n */\nasync function resolveGithubFetchRef(params: {\n parsed: ParsedSource;\n locked: LockedSource | undefined;\n updateSources: boolean;\n sourceKey: string;\n client: GitHubClient;\n logger: Logger;\n}): Promise<{ ref: string; resolvedSha: string; requestedRef: string | undefined }> {\n const { parsed, locked, updateSources, sourceKey, client, logger } = params;\n if (locked && !updateSources) {\n // Use the locked SHA for deterministic fetching\n logger.debug(`Using locked ref for ${sourceKey}: ${locked.resolvedRef}`);\n return {\n ref: locked.resolvedRef,\n resolvedSha: locked.resolvedRef,\n requestedRef: locked.requestedRef,\n };\n }\n // Resolve the ref (or default branch) to a SHA\n const requestedRef = parsed.ref ?? (await client.getDefaultBranch(parsed.owner, parsed.repo));\n const resolvedSha = await client.resolveRefToSha(parsed.owner, parsed.repo, requestedRef);\n logger.debug(`Resolved ${sourceKey} ref \"${requestedRef}\" to SHA: ${resolvedSha}`);\n return { ref: resolvedSha, resolvedSha, requestedRef };\n}\n\n/**\n * Fallback path used when an explicit single-skill source points at a flat skill\n * with root-level files. Fetches and writes that skill into `fetchedSkills`.\n * Returns whether the fallback fired and the resulting remote skill names.\n */\nasync function fetchRootLevelFallbackSkill(params: {\n entries: GitHubFileEntry[];\n parsed: ParsedSource;\n ref: string;\n resolvedSha: string;\n skillFilter: string[];\n isWildcard: boolean;\n curatedDir: string;\n locked: LockedSource | undefined;\n sourceKey: string;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n client: GitHubClient;\n semaphore: Semaphore;\n fetchedSkills: Record<string, LockedSkill>;\n logger: Logger;\n}): Promise<{ handled: boolean; remoteSkillNames: string[] }> {\n const {\n entries,\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n } = params;\n\n const rootFiles = entries.filter((entry) => entry.type === \"file\");\n const rootSkillFiles: RemoteSkillFile[] = [];\n\n for (const file of rootFiles) {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping file \"${file.path}\" (${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n continue;\n }\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, file.path, ref),\n );\n rootSkillFiles.push({ relativePath: file.name, content });\n }\n\n const groupedRootFiles = groupRemoteFilesBySkillRoot({\n remoteFiles: rootSkillFiles,\n skillFilter,\n isWildcard,\n });\n const [fallbackSkillName] = groupedRootFiles.keys();\n if (fallbackSkillName === undefined) {\n return { handled: false, remoteSkillNames: [] };\n }\n\n if (\n !shouldSkipSkill({\n skillName: fallbackSkillName,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n fetchedSkills[fallbackSkillName] = await writeSkillAndComputeIntegrity({\n skillName: fallbackSkillName,\n files: groupedRootFiles.get(fallbackSkillName) ?? [],\n curatedDir,\n locked,\n resolvedSha,\n sourceKey,\n logger,\n });\n logger.debug(`Fetched skill \"${fallbackSkillName}\" from ${sourceKey}`);\n }\n\n return { handled: true, remoteSkillNames: [fallbackSkillName] };\n}\n\n/**\n * Recursively fetch and write a single skill directory's files via the GitHub\n * REST API, returning its computed LockedSkill entry.\n */\nasync function fetchGithubSkillDir(params: {\n skillDir: { name: string; path: string };\n parsed: ParsedSource;\n ref: string;\n resolvedSha: string;\n curatedDir: string;\n locked: LockedSource | undefined;\n sourceKey: string;\n client: GitHubClient;\n semaphore: Semaphore;\n logger: Logger;\n}): Promise<LockedSkill> {\n const {\n skillDir,\n parsed,\n ref,\n resolvedSha,\n curatedDir,\n locked,\n sourceKey,\n client,\n semaphore,\n logger,\n } = params;\n\n // Recursively fetch all files in this skill directory\n const allFiles = await listDirectoryRecursive({\n client,\n owner: parsed.owner,\n repo: parsed.repo,\n path: skillDir.path,\n ref,\n semaphore,\n });\n\n // Filter out files exceeding MAX_FILE_SIZE\n const files = allFiles.filter((file) => {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping file \"${file.path}\" (${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n return false;\n }\n return true;\n });\n\n // Fetch all file contents\n const skillFiles: Array<{ relativePath: string; content: string }> = [];\n for (const file of files) {\n const relativeToSkill = file.path.substring(skillDir.path.length + 1);\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, file.path, ref),\n );\n skillFiles.push({ relativePath: relativeToSkill, content });\n }\n\n return writeSkillAndComputeIntegrity({\n skillName: skillDir.name,\n files: skillFiles,\n curatedDir,\n locked,\n resolvedSha,\n sourceKey,\n logger,\n });\n}\n\n/**\n * List the remote skills directory and apply the root-level fallback. Returns a\n * `notFound` sentinel when the directory 404s (so the caller can skip the\n * source), otherwise the discovered skill subdirectories plus any fallback skill\n * names already written into `fetchedSkills`.\n */\nasync function discoverGithubSkillDirs(params: {\n parsed: ParsedSource;\n ref: string;\n resolvedSha: string;\n skillFilter: string[];\n isWildcard: boolean;\n curatedDir: string;\n locked: LockedSource | undefined;\n sourceKey: string;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n client: GitHubClient;\n semaphore: Semaphore;\n fetchedSkills: Record<string, LockedSkill>;\n logger: Logger;\n}): Promise<\n | { status: \"notFound\" }\n | {\n status: \"ok\";\n remoteSkillDirs: Array<{ name: string; path: string }>;\n fallbackHandled: boolean;\n remoteSkillNames: string[];\n }\n> {\n const {\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n } = params;\n\n const skillsBasePath = parsed.path ?? \"skills\";\n try {\n const entries = await client.listDirectory(parsed.owner, parsed.repo, skillsBasePath, ref);\n const remoteSkillDirs = entries\n .filter((e) => e.type === \"dir\")\n .map((e) => ({ name: e.name, path: e.path }));\n\n const [singleSkillName] = skillFilter;\n const hasRequestedSkillDir =\n singleSkillName !== undefined && remoteSkillDirs.some((d) => d.name === singleSkillName);\n // Detect a root-level SKILL.md from the directory listing we already have, so\n // the fallback (and its full root-file fetch) is skipped when there is no\n // root skill to install — not just when the requested dir is absent.\n const hasRootSkillFile = entries.some(\n (entry) => entry.type === \"file\" && entry.name === SKILL_FILE_NAME,\n );\n if (\n shouldUseRootFallback({ skillFilter, isWildcard, hasRootSkillFile, hasRequestedSkillDir })\n ) {\n const fallback = await fetchRootLevelFallbackSkill({\n entries,\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n });\n if (fallback.handled) {\n return {\n status: \"ok\",\n remoteSkillDirs,\n fallbackHandled: true,\n remoteSkillNames: fallback.remoteSkillNames,\n };\n }\n }\n\n return { status: \"ok\", remoteSkillDirs, fallbackHandled: false, remoteSkillNames: [] };\n } catch (error) {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return { status: \"notFound\" };\n }\n throw error;\n }\n}\n\n/**\n * Fetch skills from a single source entry via the GitHub REST API.\n */\nasync function fetchSource(params: {\n sourceEntry: SourceEntry;\n client: GitHubClient;\n projectRoot: string;\n lock: SourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n logger: Logger;\n}): Promise<{\n skillCount: number;\n fetchedSkillNames: string[];\n updatedLock: SourcesLock;\n}> {\n const {\n sourceEntry,\n client,\n projectRoot,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n logger,\n } = params;\n const { lock } = params;\n\n const parsed = parseSource(sourceEntry.source);\n\n if (parsed.provider === \"gitlab\") {\n logger.warn(`GitLab sources are not yet supported. Skipping \"${sourceEntry.source}\".`);\n return { skillCount: 0, fetchedSkillNames: [], updatedLock: lock };\n }\n\n const sourceKey = sourceEntry.source;\n const locked = getLockedSource(lock, sourceKey);\n const lockedSkillNames = locked ? getLockedSkillNames(locked) : [];\n\n // Resolve the ref to a commit SHA\n const { ref, resolvedSha, requestedRef } = await resolveGithubFetchRef({\n parsed,\n locked,\n updateSources,\n sourceKey,\n client,\n logger,\n });\n\n const curatedDir = join(projectRoot, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);\n\n // Skip re-fetch if SHA matches lockfile and curated skills exist on disk\n if (locked && resolvedSha === locked.resolvedRef && !updateSources) {\n const allExist = await checkLockedSkillsExist(curatedDir, lockedSkillNames);\n if (allExist) {\n logger.debug(`SHA unchanged for ${sourceKey}, skipping re-fetch.`);\n return {\n skillCount: 0,\n fetchedSkillNames: lockedSkillNames,\n updatedLock: lock,\n };\n }\n }\n\n // Determine which skills to fetch\n const skillFilter = sourceEntry.skills ?? [\"*\"];\n const isWildcard = skillFilter.length === 1 && skillFilter[0] === \"*\";\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n const fetchedSkills: Record<string, LockedSkill> = {};\n\n // List the skills/ directory in the remote repo.\n // If a path is given in the source URL, it points directly to the skills directory.\n // Otherwise, look for \"skills/\" at the repo root.\n const discovery = await discoverGithubSkillDirs({\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n });\n if (discovery.status === \"notFound\") {\n logger.warn(`No skills/ directory found in ${sourceKey}. Skipping.`);\n return { skillCount: 0, fetchedSkillNames: [], updatedLock: lock };\n }\n const { remoteSkillDirs, fallbackHandled, remoteSkillNames: fallbackSkillNames } = discovery;\n\n // Filter skills by name\n const filteredDirs = isWildcard\n ? remoteSkillDirs\n : remoteSkillDirs.filter((d) => skillFilter.includes(d.name));\n const remoteSkillNames = fallbackHandled ? fallbackSkillNames : filteredDirs.map((d) => d.name);\n\n if (locked) {\n await cleanPreviousCuratedSkills({ curatedDir, lockedSkillNames, logger });\n }\n\n for (const skillDir of filteredDirs) {\n if (\n shouldSkipSkill({\n skillName: skillDir.name,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n continue;\n }\n\n fetchedSkills[skillDir.name] = await fetchGithubSkillDir({\n skillDir,\n parsed,\n ref,\n resolvedSha,\n curatedDir,\n locked,\n sourceKey,\n client,\n semaphore,\n logger,\n });\n logger.debug(`Fetched skill \"${skillDir.name}\" from ${sourceKey}`);\n }\n\n const result = buildLockUpdate({\n lock,\n sourceKey,\n fetchedSkills,\n locked,\n requestedRef,\n resolvedSha,\n remoteSkillNames,\n logger,\n });\n\n return {\n skillCount: result.fetchedNames.length,\n fetchedSkillNames: result.fetchedNames,\n updatedLock: result.updatedLock,\n };\n}\n\n/**\n * Fetch skills from a single source using git CLI (works with any git remote).\n */\nasync function fetchSourceViaGit(params: {\n sourceEntry: SourceEntry;\n projectRoot: string;\n lock: SourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n frozen: boolean;\n logger: Logger;\n}): Promise<{ skillCount: number; fetchedSkillNames: string[]; updatedLock: SourcesLock }> {\n const {\n sourceEntry,\n projectRoot,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n frozen,\n logger,\n } = params;\n const { lock } = params;\n const url = sourceEntry.source;\n const locked = getLockedSource(lock, url);\n const lockedSkillNames = locked ? getLockedSkillNames(locked) : [];\n\n let resolvedSha: string;\n let requestedRef: string | undefined;\n if (locked && !updateSources) {\n resolvedSha = locked.resolvedRef;\n requestedRef = locked.requestedRef;\n // Validate locked ref before passing to git commands\n if (requestedRef) {\n validateRef(requestedRef);\n }\n } else if (sourceEntry.ref) {\n requestedRef = sourceEntry.ref;\n resolvedSha = await resolveRefToSha(url, requestedRef);\n } else {\n const def = await resolveDefaultRef(url);\n requestedRef = def.ref;\n resolvedSha = def.sha;\n }\n\n const curatedDir = join(projectRoot, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);\n if (locked && resolvedSha === locked.resolvedRef && !updateSources) {\n if (await checkLockedSkillsExist(curatedDir, lockedSkillNames)) {\n return { skillCount: 0, fetchedSkillNames: lockedSkillNames, updatedLock: lock };\n }\n }\n\n // Resolve requestedRef lazily (deferred from locked path to avoid unnecessary network calls)\n if (!requestedRef) {\n if (frozen) {\n throw new Error(\n `Frozen install failed: lockfile entry for \"${url}\" is missing requestedRef. Run 'rulesync install' to update the lockfile.`,\n );\n }\n const def = await resolveDefaultRef(url);\n requestedRef = def.ref;\n resolvedSha = def.sha;\n }\n\n const skillFilter = sourceEntry.skills ?? [\"*\"];\n const isWildcard = skillFilter.length === 1 && skillFilter[0] === \"*\";\n const remoteFiles = await fetchSkillFiles({\n url,\n ref: requestedRef,\n skillsPath: sourceEntry.path ?? \"skills\",\n });\n\n const skillFileMap = groupRemoteFilesBySkillRoot({ remoteFiles, skillFilter, isWildcard });\n\n const allNames = [...skillFileMap.keys()];\n const filteredNames = isWildcard ? allNames : allNames.filter((n) => skillFilter.includes(n));\n\n if (locked) {\n await cleanPreviousCuratedSkills({ curatedDir, lockedSkillNames, logger });\n }\n\n const fetchedSkills: Record<string, LockedSkill> = {};\n for (const skillName of filteredNames) {\n if (\n shouldSkipSkill({\n skillName,\n sourceKey: url,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n continue;\n }\n\n fetchedSkills[skillName] = await writeSkillAndComputeIntegrity({\n skillName,\n files: skillFileMap.get(skillName) ?? [],\n curatedDir,\n locked,\n resolvedSha,\n sourceKey: url,\n logger,\n });\n }\n\n const result = buildLockUpdate({\n lock,\n sourceKey: url,\n fetchedSkills,\n locked,\n requestedRef,\n resolvedSha,\n remoteSkillNames: filteredNames,\n logger,\n });\n return {\n skillCount: result.fetchedNames.length,\n fetchedSkillNames: result.fetchedNames,\n updatedLock: result.updatedLock,\n };\n}\n","import { ConfigResolver } from \"../../config/config-resolver.js\";\nimport { installApm } from \"../../lib/apm/apm-install.js\";\nimport { apmManifestExists } from \"../../lib/apm/apm-manifest.js\";\nimport { installGh } from \"../../lib/gh/gh-install.js\";\nimport { resolveAndFetchSources } from \"../../lib/sources.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\nexport const INSTALL_MODES = [\"rulesync\", \"apm\", \"gh\"] as const;\nexport type InstallMode = (typeof INSTALL_MODES)[number];\n\nexport type InstallCommandOptions = {\n mode?: InstallMode;\n update?: boolean;\n frozen?: boolean;\n token?: string;\n configPath?: string;\n verbose?: boolean;\n silent?: boolean;\n};\n\nexport async function installCommand(\n logger: Logger,\n options: InstallCommandOptions,\n): Promise<void> {\n const mode: InstallMode = options.mode ?? \"rulesync\";\n\n if (mode === \"gh\") {\n await runGhInstall(logger, options);\n return;\n }\n\n if (mode === \"apm\") {\n await runApmInstall(logger, options);\n return;\n }\n\n await runRulesyncInstall(logger, options);\n}\n\nasync function runRulesyncInstall(logger: Logger, options: InstallCommandOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n // If both apm.yml and rulesync.jsonc sources are defined, refuse to guess.\n // `--mode apm` is required to opt into the APM layout.\n const apmExists = await apmManifestExists(projectRoot);\n\n const config = await ConfigResolver.resolve({\n configPath: options.configPath,\n verbose: options.verbose,\n silent: options.silent,\n });\n const sources = config.getSources();\n\n if (apmExists && sources.length > 0) {\n throw new Error(\n \"Both apm.yml and rulesync.jsonc `sources` are defined. Pass --mode apm or --mode rulesync to disambiguate.\",\n );\n }\n\n if (sources.length === 0) {\n if (apmExists) {\n logger.warn(\n \"No sources defined in rulesync.jsonc, but apm.yml is present. Did you mean --mode apm?\",\n );\n return;\n }\n logger.warn(\"No sources defined in configuration. Nothing to install.\");\n return;\n }\n\n logger.debug(`Installing skills from ${sources.length} source(s)...`);\n\n const result = await resolveAndFetchSources({\n sources,\n projectRoot,\n options: {\n updateSources: options.update,\n frozen: options.frozen,\n token: options.token,\n },\n logger,\n });\n\n if (logger.jsonMode) {\n logger.captureData(\"sourcesProcessed\", result.sourcesProcessed);\n logger.captureData(\"skillsFetched\", result.fetchedSkillCount);\n }\n\n if (result.fetchedSkillCount > 0) {\n logger.success(\n `Installed ${result.fetchedSkillCount} skill(s) from ${result.sourcesProcessed} source(s).`,\n );\n } else {\n logger.success(`All skills up to date (${result.sourcesProcessed} source(s) checked).`);\n }\n}\n\nasync function runApmInstall(logger: Logger, options: InstallCommandOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n if (!(await apmManifestExists(projectRoot))) {\n throw new Error(\n \"--mode apm requires an apm.yml at the project root. Create one or drop --mode apm to fall back to rulesync mode.\",\n );\n }\n\n const result = await installApm({\n projectRoot,\n options: {\n update: options.update,\n frozen: options.frozen,\n token: options.token,\n },\n logger,\n });\n\n if (logger.jsonMode) {\n logger.captureData(\"dependenciesProcessed\", result.dependenciesProcessed);\n logger.captureData(\"deployedFileCount\", result.deployedFileCount);\n logger.captureData(\"failedDependencyCount\", result.failedDependencyCount);\n }\n\n if (result.failedDependencyCount > 0) {\n throw new Error(\n `Failed to install ${result.failedDependencyCount} of ${result.dependenciesProcessed} apm dependency(ies). See the log above for details.`,\n );\n }\n\n if (result.deployedFileCount > 0) {\n logger.success(\n `Installed ${result.deployedFileCount} file(s) from ${result.dependenciesProcessed} apm dependency(ies).`,\n );\n } else {\n logger.success(`All apm dependencies up to date (${result.dependenciesProcessed} checked).`);\n }\n}\n\nasync function runGhInstall(logger: Logger, options: InstallCommandOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n // gh mode reads sources from `rulesync.jsonc`, never from `apm.yml`. The\n // disambiguation between rulesync/apm modes lives in `runRulesyncInstall`;\n // here the user has already opted into gh mode explicitly.\n const config = await ConfigResolver.resolve({\n configPath: options.configPath,\n verbose: options.verbose,\n silent: options.silent,\n });\n const sources = config.getSources();\n\n if (sources.length === 0) {\n logger.warn(\"No sources defined in configuration. Nothing to install.\");\n return;\n }\n\n const result = await installGh({\n projectRoot,\n sources,\n options: {\n update: options.update,\n frozen: options.frozen,\n token: options.token,\n },\n logger,\n });\n\n if (logger.jsonMode) {\n logger.captureData(\"sourcesProcessed\", result.sourcesProcessed);\n logger.captureData(\"installedSkillCount\", result.installedSkillCount);\n logger.captureData(\"failedSourceCount\", result.failedSourceCount);\n }\n\n if (result.failedSourceCount > 0) {\n throw new Error(\n `Failed to install ${result.failedSourceCount} of ${result.sourcesProcessed} gh source(s). See the log above for details.`,\n );\n }\n\n if (result.installedSkillCount > 0) {\n logger.success(\n `Installed ${result.installedSkillCount} skill(s) from ${result.sourcesProcessed} gh source(s).`,\n );\n } else {\n logger.success(`All gh sources up to date (${result.sourcesProcessed} checked).`);\n }\n}\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_CHECKS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncCheck,\n type RulesyncCheckFrontmatter,\n RulesyncCheckFrontmatterSchema,\n} from \"../features/checks/rulesync-check.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxCheckSizeBytes = 1024 * 1024; // 1MB\nconst maxChecksCount = 1000;\n\n/**\n * Tool to list all checks from .rulesync/checks/*.md\n */\nasync function listChecks(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n }>\n> {\n const checksDir = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(checksDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const checks = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n const check = await RulesyncCheck.fromFile({\n relativeFilePath: file,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, file),\n frontmatter: check.getFrontmatter(),\n };\n } catch (error) {\n logger.error(`Failed to read check file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return checks.filter((check): check is NonNullable<typeof check> => check !== null);\n } catch (error) {\n logger.error(\n `Failed to read checks directory (${RULESYNC_CHECKS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific check\n */\nasync function getCheck({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const check = await RulesyncCheck.fromFile({\n relativeFilePath: filename,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n frontmatter: check.getFrontmatter(),\n body: check.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read check file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a check (upsert operation)\n */\nasync function putCheck({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxCheckSizeBytes) {\n throw new Error(\n `Check size ${estimatedSize} bytes exceeds maximum ${maxCheckSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check count constraint\n const existingChecks = await listChecks();\n const isUpdate = existingChecks.some(\n (check) => check.relativePathFromCwd === join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingChecks.length >= maxChecksCount) {\n throw new Error(\n `Maximum number of checks (${maxChecksCount}) reached in ${RULESYNC_CHECKS_RELATIVE_DIR_PATH}`,\n );\n }\n\n const check = new RulesyncCheck({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n validate: true,\n });\n\n // Ensure directory exists\n const checksDir = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH);\n await ensureDir(checksDir);\n\n // Write the file\n await writeFileContent(check.getFilePath(), check.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n frontmatter: check.getFrontmatter(),\n body: check.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write check file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a check\n */\nasync function deleteCheck({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(`Failed to delete check file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Schema for check-related tool parameters\n */\nconst checkToolSchemas = {\n listChecks: z.object({}),\n getCheck: z.object({\n relativePathFromCwd: z.string(),\n }),\n putCheck: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncCheckFrontmatterSchema,\n body: z.string(),\n }),\n deleteCheck: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for check-related operations\n */\nexport const checkTools = {\n listChecks: {\n name: \"listChecks\",\n description: `List all checks from ${join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: checkToolSchemas.listChecks,\n execute: async () => {\n const checks = await listChecks();\n const output = { checks };\n return JSON.stringify(output, null, 2);\n },\n },\n getCheck: {\n name: \"getCheck\",\n description:\n \"Get detailed information about a specific check. relativePathFromCwd parameter is required.\",\n parameters: checkToolSchemas.getCheck,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getCheck({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putCheck: {\n name: \"putCheck\",\n description:\n \"Create or update a check (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: checkToolSchemas.putCheck,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n }) => {\n const result = await putCheck({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteCheck: {\n name: \"deleteCheck\",\n description: \"Delete a check file. relativePathFromCwd parameter is required.\",\n parameters: checkToolSchemas.deleteCheck,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteCheck({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_COMMANDS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncCommand,\n type RulesyncCommandFrontmatter,\n RulesyncCommandFrontmatterSchema,\n} from \"../features/commands/rulesync-command.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { stringifyFrontmatter } from \"../utils/frontmatter.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxCommandSizeBytes = 1024 * 1024; // 1MB\nconst maxCommandsCount = 1000;\n\n/**\n * Tool to list all commands from .rulesync/commands/*.md\n */\nasync function listCommands(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n }>\n> {\n const commandsDir = join(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(commandsDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const commands = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n checkPathTraversal({\n relativePath: file,\n intendedRootDir: commandsDir,\n });\n\n const command = await RulesyncCommand.fromFile({\n relativeFilePath: file,\n });\n\n const frontmatter = command.getFrontmatter();\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read command file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return commands.filter((command): command is NonNullable<typeof command> => command !== null);\n } catch (error) {\n logger.error(\n `Failed to read commands directory (${RULESYNC_COMMANDS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific command\n */\nasync function getCommand({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const command = await RulesyncCommand.fromFile({\n relativeFilePath: filename,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n frontmatter: command.getFrontmatter(),\n body: command.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read command file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a command (upsert operation)\n */\nasync function putCommand({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxCommandSizeBytes) {\n throw new Error(\n `Command size ${estimatedSize} bytes exceeds maximum ${maxCommandSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check command count constraint\n const existingCommands = await listCommands();\n const isUpdate = existingCommands.some(\n (command) =>\n command.relativePathFromCwd === join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingCommands.length >= maxCommandsCount) {\n throw new Error(\n `Maximum number of commands (${maxCommandsCount}) reached in ${RULESYNC_COMMANDS_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Create a new RulesyncCommand instance\n const fileContent = stringifyFrontmatter(body, frontmatter);\n const command = new RulesyncCommand({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_COMMANDS_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n fileContent,\n validate: true,\n });\n\n // Ensure directory exists\n const commandsDir = join(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);\n await ensureDir(commandsDir);\n\n // Write the file\n await writeFileContent(command.getFilePath(), command.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n frontmatter: command.getFrontmatter(),\n body: command.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write command file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a command\n */\nasync function deleteCommand({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Schema for command-related tool parameters\n */\nconst commandToolSchemas = {\n listCommands: z.object({}),\n getCommand: z.object({\n relativePathFromCwd: z.string(),\n }),\n putCommand: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncCommandFrontmatterSchema,\n body: z.string(),\n }),\n deleteCommand: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for command-related operations\n */\nexport const commandTools = {\n listCommands: {\n name: \"listCommands\",\n description: `List all commands from ${join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: commandToolSchemas.listCommands,\n execute: async () => {\n const commands = await listCommands();\n const output = { commands };\n return JSON.stringify(output, null, 2);\n },\n },\n getCommand: {\n name: \"getCommand\",\n description:\n \"Get detailed information about a specific command. relativePathFromCwd parameter is required.\",\n parameters: commandToolSchemas.getCommand,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getCommand({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putCommand: {\n name: \"putCommand\",\n description:\n \"Create or update a command (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: commandToolSchemas.putCommand,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n }) => {\n const result = await putCommand({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteCommand: {\n name: \"deleteCommand\",\n description: \"Delete a command file. relativePathFromCwd parameter is required.\",\n parameters: commandToolSchemas.deleteCommand,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteCommand({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { z } from \"zod/mini\";\n\nimport { ConfigResolver } from \"../config/config-resolver.js\";\nimport { Config } from \"../config/config.js\";\nimport { convertFromTool, type ConvertResult } from \"../lib/convert.js\";\nimport { type RulesyncFeatures } from \"../types/features.js\";\nimport { ALL_TOOL_TARGETS, type ToolTarget, ToolTargetSchema } from \"../types/tool-targets.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\nimport { calculateTotalCount } from \"../utils/result.js\";\nimport { type McpResultCounts } from \"./types.js\";\n\n/**\n * Schema for convert options\n * Excluded parameters:\n * - outputRoots: Always use [process.cwd()] in MCP context\n * - verbose: Meaningless in MCP (no console output)\n * - silent: Meaningless in MCP\n * - configPath: Always use default path from process.cwd()\n */\nexport const convertOptionsSchema = z.object({\n from: z.string(),\n to: z.array(z.string()),\n features: z.optional(z.array(z.string())),\n global: z.optional(z.boolean()),\n dryRun: z.optional(z.boolean()),\n});\n\nexport type ConvertOptions = z.infer<typeof convertOptionsSchema>;\n\nexport type McpConvertResult = {\n success: boolean;\n result?: McpResultCounts;\n config?: {\n from: string;\n to: string[];\n features: string[];\n global: boolean;\n dryRun: boolean;\n };\n error?: string;\n};\n\nfunction parseToolTarget(value: string, label: string): ToolTarget {\n const result = ToolTargetSchema.safeParse(value);\n if (!result.success) {\n throw new Error(\n `Invalid ${label} tool '${value}'. Must be one of: ${ALL_TOOL_TARGETS.join(\", \")}`,\n );\n }\n return result.data;\n}\n\n/**\n * Execute the rulesync convert command via MCP\n * Configuration priority: MCP Parameters > rulesync.local.jsonc > rulesync.jsonc > Default values\n */\nexport async function executeConvert(options: ConvertOptions): Promise<McpConvertResult> {\n try {\n // Validate from\n if (!options.from) {\n return {\n success: false,\n error: \"from is required. Please specify a source tool to convert from.\",\n };\n }\n\n // Validate to\n if (!options.to || options.to.length === 0) {\n return {\n success: false,\n error: \"to is required and must not be empty. Please specify destination tools.\",\n };\n }\n\n const fromTool = parseToolTarget(options.from, \"source\");\n const toToolsRaw = options.to.map((t) => parseToolTarget(t, \"destination\"));\n const toTools = Array.from(new Set(toToolsRaw));\n\n if (toTools.includes(fromTool)) {\n return {\n success: false,\n error:\n `Destination tools must not include the source tool '${fromTool}'. ` +\n `Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`,\n };\n }\n\n // Resolve config with MCP parameters taking precedence\n // ConfigResolver handles: CLI options > rulesync.local.jsonc > rulesync.jsonc > defaults\n // In MCP context, options act as CLI options (highest priority)\n // Pass both source and destinations as `targets` so per-target feature maps\n // in `rulesync.jsonc` are honored for every tool involved. Default features\n // to `*` so every feature that both tools support is attempted.\n const config = await ConfigResolver.resolve({\n targets: [fromTool, ...toTools],\n features: (options.features ?? [\"*\"]) as RulesyncFeatures,\n global: options.global,\n dryRun: options.dryRun,\n // Always use default outputRoots (process.cwd()) and configPath\n // verbose and silent are meaningless in MCP context\n verbose: false,\n silent: true,\n });\n\n const logger = new ConsoleLogger({ verbose: false, silent: true });\n const convertResult = await convertFromTool({ config, fromTool, toTools, logger });\n\n return buildSuccessResponse({ convertResult, config, fromTool, toTools });\n } catch (error) {\n return {\n success: false,\n error: formatError(error),\n };\n }\n}\n\nfunction buildSuccessResponse(params: {\n convertResult: ConvertResult;\n config: Config;\n fromTool: ToolTarget;\n toTools: ToolTarget[];\n}): McpConvertResult {\n const { convertResult, config, fromTool, toTools } = params;\n\n const totalCount = calculateTotalCount(convertResult);\n\n return {\n success: true,\n result: {\n rulesCount: convertResult.rulesCount,\n ignoreCount: convertResult.ignoreCount,\n mcpCount: convertResult.mcpCount,\n commandsCount: convertResult.commandsCount,\n subagentsCount: convertResult.subagentsCount,\n skillsCount: convertResult.skillsCount,\n hooksCount: convertResult.hooksCount,\n permissionsCount: convertResult.permissionsCount,\n checksCount: convertResult.checksCount,\n totalCount,\n },\n config: {\n from: fromTool,\n to: toTools,\n features: config.getFeatures(),\n global: config.getGlobal(),\n dryRun: config.isPreviewMode(),\n },\n };\n}\n\nconst convertToolSchemas = {\n executeConvert: convertOptionsSchema,\n};\n\nexport const convertTools = {\n executeConvert: {\n name: \"executeConvert\",\n description:\n \"Execute the rulesync convert command to convert configuration files between AI tools without writing intermediate .rulesync/ files. Requires a source tool (from) and one or more destination tools (to).\",\n parameters: convertToolSchemas.executeConvert,\n execute: async (options: ConvertOptions): Promise<string> => {\n const result = await executeConvert(options);\n return JSON.stringify(result, null, 2);\n },\n },\n};\n","import { z } from \"zod/mini\";\n\nimport { ConfigResolver } from \"../config/config-resolver.js\";\nimport { Config } from \"../config/config.js\";\nimport { checkRulesyncDirExists, generate, type GenerateResult } from \"../lib/generate.js\";\nimport { type RulesyncFeatures } from \"../types/features.js\";\nimport { type RulesyncTargets } from \"../types/tool-targets.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\nimport { calculateTotalCount } from \"../utils/result.js\";\nimport { type McpResultCounts } from \"./types.js\";\n\n/**\n * Schema for generate options\n * Excluded parameters:\n * - outputRoots: Always use [process.cwd()] in MCP context\n * - verbose: Meaningless in MCP (no console output)\n * - silent: Meaningless in MCP\n * - configPath: Always use default path from process.cwd()\n */\nexport const generateOptionsSchema = z.object({\n targets: z.optional(z.array(z.string())),\n features: z.optional(z.array(z.string())),\n delete: z.optional(z.boolean()),\n global: z.optional(z.boolean()),\n simulateCommands: z.optional(z.boolean()),\n simulateSubagents: z.optional(z.boolean()),\n simulateSkills: z.optional(z.boolean()),\n});\n\nexport type GenerateOptions = z.infer<typeof generateOptionsSchema>;\n\nexport type McpGenerateResult = {\n success: boolean;\n /**\n * Human-readable summary of the outcome. Clarifies that a `totalCount` of 0\n * means \"already up to date\" (success with nothing to write) rather than a\n * failure, since `generate` is idempotent and only writes changed files.\n */\n message?: string;\n result?: McpResultCounts;\n config?: {\n targets: string[];\n features: string[];\n global: boolean;\n delete: boolean;\n simulateCommands: boolean;\n simulateSubagents: boolean;\n simulateSkills: boolean;\n };\n error?: string;\n};\n\n/**\n * Execute the rulesync generate command via MCP\n * Configuration priority: MCP Parameters > rulesync.local.jsonc > rulesync.jsonc > Default values\n */\nexport async function executeGenerate(options: GenerateOptions = {}): Promise<McpGenerateResult> {\n try {\n // Check if .rulesync directory exists\n const exists = await checkRulesyncDirExists({ inputRoot: process.cwd() });\n if (!exists) {\n return {\n success: false,\n error:\n \".rulesync directory does not exist. Please run 'rulesync init' first or create the directory manually.\",\n };\n }\n\n // Resolve config with MCP parameters taking precedence\n // ConfigResolver handles: CLI options > rulesync.local.jsonc > rulesync.jsonc > defaults\n // In MCP context, options act as CLI options (highest priority)\n const config = await ConfigResolver.resolve({\n targets: options.targets as RulesyncTargets | undefined,\n features: options.features as RulesyncFeatures | undefined,\n delete: options.delete,\n global: options.global,\n simulateCommands: options.simulateCommands,\n simulateSubagents: options.simulateSubagents,\n simulateSkills: options.simulateSkills,\n // Always use default outputRoots (process.cwd()) and configPath\n // verbose and silent are meaningless in MCP context\n verbose: false,\n silent: true,\n });\n\n const logger = new ConsoleLogger({ verbose: false, silent: true });\n const generateResult = await generate({ config, logger });\n\n return buildSuccessResponse({ generateResult, config });\n } catch (error) {\n return {\n success: false,\n error: formatError(error),\n };\n }\n}\n\n/**\n * Build a human-readable summary of a successful generation.\n *\n * `generate` is idempotent: `totalCount` reflects only files whose content\n * actually changed on disk, so a count of 0 is a normal \"nothing to update\"\n * outcome — not a failure. The message makes that explicit so MCP callers do\n * not misread a zero count as a broken generate.\n */\nfunction buildGenerateMessage(params: { totalCount: number; config: Config }): string {\n const { totalCount, config } = params;\n const targets = config.getTargets().join(\", \");\n const features = config.getFeatures().join(\", \");\n\n if (totalCount > 0) {\n return `Generated ${totalCount} file(s) for targets [${targets}] and features [${features}].`;\n }\n\n return (\n `No files needed updating for targets [${targets}] and features [${features}]. ` +\n `'generate' only writes files whose content changed, so a totalCount of 0 means the ` +\n `outputs are already up to date — this is a successful no-op, not a failure.`\n );\n}\n\nfunction buildSuccessResponse(params: {\n generateResult: GenerateResult;\n config: Config;\n}): McpGenerateResult {\n const { generateResult, config } = params;\n\n const totalCount = calculateTotalCount(generateResult);\n\n return {\n success: true,\n message: buildGenerateMessage({ totalCount, config }),\n result: {\n rulesCount: generateResult.rulesCount,\n ignoreCount: generateResult.ignoreCount,\n mcpCount: generateResult.mcpCount,\n commandsCount: generateResult.commandsCount,\n subagentsCount: generateResult.subagentsCount,\n skillsCount: generateResult.skillsCount,\n hooksCount: generateResult.hooksCount,\n permissionsCount: generateResult.permissionsCount,\n checksCount: generateResult.checksCount,\n totalCount,\n },\n config: {\n targets: config.getTargets(),\n features: config.getFeatures(),\n global: config.getGlobal(),\n delete: config.getDelete(),\n simulateCommands: config.getSimulateCommands(),\n simulateSubagents: config.getSimulateSubagents(),\n simulateSkills: config.getSimulateSkills(),\n },\n };\n}\n\nconst generateToolSchemas = {\n executeGenerate: generateOptionsSchema,\n};\n\nexport const generateTools = {\n executeGenerate: {\n name: \"executeGenerate\",\n description:\n \"Execute the rulesync generate command to create output files for AI tools. Uses rulesync.jsonc settings by default, but options can override them. Idempotent: only files whose content changed are written, so a totalCount of 0 means the outputs are already up to date (a successful no-op), not a failure. See the 'message' field for a human-readable summary.\",\n parameters: generateToolSchemas.executeGenerate,\n execute: async (options: GenerateOptions = {}): Promise<string> => {\n const result = await executeGenerate(options);\n return JSON.stringify(result, null, 2);\n },\n },\n};\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_HOOKS_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { RulesyncHooks } from \"../features/hooks/rulesync-hooks.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, fileExists, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxHooksSizeBytes = 1024 * 1024; // 1MB\n\n/**\n * Tool to get the hooks configuration file\n */\nasync function getHooksFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n try {\n const rulesyncHooks = await RulesyncHooks.fromFile({\n validate: true,\n });\n\n const relativePathFromCwd = join(\n rulesyncHooks.getRelativeDirPath(),\n rulesyncHooks.getRelativeFilePath(),\n );\n\n return {\n relativePathFromCwd,\n content: rulesyncHooks.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to read hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the hooks configuration file (upsert operation)\n */\nasync function putHooksFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n // Check file size constraint\n if (content.length > maxHooksSizeBytes) {\n throw new Error(\n `Hooks file size ${content.length} bytes exceeds maximum ${maxHooksSizeBytes} bytes (1MB) for ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}`,\n );\n }\n\n // Validate JSON format\n try {\n JSON.parse(content);\n } catch (error) {\n throw new Error(\n `Invalid JSON format in hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncHooks.getSettablePaths();\n\n // A .jsonc variant takes precedence at read time, so writing the .json\n // variant while it exists would be silently ignored — and rewriting the\n // .jsonc file here would destroy its comments. Refuse instead.\n const jsoncRelativePath = join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);\n if (await fileExists(join(outputRoot, jsoncRelativePath))) {\n throw new Error(\n `${jsoncRelativePath} exists and takes precedence over ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}. Edit ${jsoncRelativePath} directly instead.`,\n );\n }\n\n const relativeDirPath = paths.relativeDirPath;\n const relativeFilePath = paths.relativeFilePath;\n const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);\n\n // Create a RulesyncHooks instance to validate the content\n const rulesyncHooks = new RulesyncHooks({\n outputRoot,\n relativeDirPath,\n relativeFilePath,\n fileContent: content,\n validate: true,\n });\n\n // Ensure directory exists\n await ensureDir(join(outputRoot, relativeDirPath));\n\n // Write the file\n await writeFileContent(fullPath, content);\n\n const relativePathFromCwd = join(relativeDirPath, relativeFilePath);\n\n return {\n relativePathFromCwd,\n content: rulesyncHooks.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to write hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the hooks configuration file\n */\nasync function deleteHooksFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncHooks.getSettablePaths();\n\n const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);\n\n await removeFile(filePath);\n\n // Remove the .jsonc variant if it exists\n await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));\n\n const relativePathFromCwd = join(paths.relativeDirPath, paths.relativeFilePath);\n\n return {\n relativePathFromCwd,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for hooks-related tool parameters\n */\nconst hooksToolSchemas = {\n getHooksFile: z.object({}),\n putHooksFile: z.object({\n content: z.string(),\n }),\n deleteHooksFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for hooks-related operations\n */\nexport const hooksTools = {\n getHooksFile: {\n name: \"getHooksFile\",\n description: `Get the hooks configuration file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}).`,\n parameters: hooksToolSchemas.getHooksFile,\n execute: async () => {\n const result = await getHooksFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putHooksFile: {\n name: \"putHooksFile\",\n description:\n \"Create or update the hooks configuration file (upsert operation). content parameter is required and must be valid JSON.\",\n parameters: hooksToolSchemas.putHooksFile,\n execute: async (args: { content: string }) => {\n const result = await putHooksFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteHooksFile: {\n name: \"deleteHooksFile\",\n description: \"Delete the hooks configuration file.\",\n parameters: hooksToolSchemas.deleteHooksFile,\n execute: async () => {\n const result = await deleteHooksFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport {\n RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n RULESYNC_IGNORE_RELATIVE_FILE_PATH,\n} from \"../constants/rulesync-paths.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, readFileContent, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxIgnoreFileSizeBytes = 100 * 1024; // 100KB\n\n/**\n * Tool to get the content of .rulesync/.aiignore file\n */\nasync function getIgnoreFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n const ignoreFilePath = join(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);\n\n try {\n const content = await readFileContent(ignoreFilePath);\n\n return {\n relativePathFromCwd: RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n content,\n };\n } catch (error) {\n throw new Error(\n `Failed to read ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the .rulesync/.aiignore file (upsert operation)\n */\nasync function putIgnoreFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n const ignoreFilePath = join(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);\n\n // Check file size constraint\n const contentSizeBytes = Buffer.byteLength(content, \"utf8\");\n if (contentSizeBytes > maxIgnoreFileSizeBytes) {\n throw new Error(\n `Ignore file size ${contentSizeBytes} bytes exceeds maximum ${maxIgnoreFileSizeBytes} bytes (100KB) for ${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}`,\n );\n }\n\n try {\n // Ensure parent directory exists (should be cwd, but just to be safe)\n await ensureDir(process.cwd());\n\n // Write the file\n await writeFileContent(ignoreFilePath, content);\n\n return {\n relativePathFromCwd: RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n content,\n };\n } catch (error) {\n throw new Error(\n `Failed to write ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the .rulesyncignore (legacy) and .rulesync/.aiignore (recommended) files\n */\nasync function deleteIgnoreFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n const aiignorePath = join(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);\n const legacyIgnorePath = join(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);\n\n try {\n // Attempt to remove both files. The removeFile helper is expected to be idempotent\n // (no-throw for non-existent files). If any real IO error happens, the Promise.all\n // will reject and we propagate an error.\n await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);\n\n return {\n // Keep the historical return shape — point to the recommended file path\n // for backward compatibility.\n relativePathFromCwd: RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete ignore files (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}, ${RULESYNC_IGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for ignore-related tool parameters\n */\nconst ignoreToolSchemas = {\n getIgnoreFile: z.object({}),\n putIgnoreFile: z.object({\n content: z.string(),\n }),\n deleteIgnoreFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for ignore-related operations\n */\nexport const ignoreTools = {\n getIgnoreFile: {\n name: \"getIgnoreFile\",\n description: \"Get the content of the .rulesyncignore file from the project root.\",\n parameters: ignoreToolSchemas.getIgnoreFile,\n execute: async () => {\n const result = await getIgnoreFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putIgnoreFile: {\n name: \"putIgnoreFile\",\n description:\n \"Create or update the .rulesync/.aiignore file (upsert operation). content parameter is required.\",\n parameters: ignoreToolSchemas.putIgnoreFile,\n execute: async (args: { content: string }) => {\n const result = await putIgnoreFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteIgnoreFile: {\n name: \"deleteIgnoreFile\",\n description: \"Delete the .rulesyncignore and .rulesync/.aiignore files.\",\n parameters: ignoreToolSchemas.deleteIgnoreFile,\n execute: async () => {\n const result = await deleteIgnoreFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { z } from \"zod/mini\";\n\nimport { ConfigResolver } from \"../config/config-resolver.js\";\nimport { Config } from \"../config/config.js\";\nimport { importFromTool, type ImportResult } from \"../lib/import.js\";\nimport { type RulesyncFeatures } from \"../types/features.js\";\nimport { type RulesyncTargets, type ToolTarget } from \"../types/tool-targets.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\nimport { calculateTotalCount } from \"../utils/result.js\";\nimport { type McpResultCounts } from \"./types.js\";\n\n/**\n * Schema for import options\n * Note: Import requires exactly one target tool\n * Excluded parameters:\n * - outputRoots: Always use [process.cwd()] in MCP context\n * - verbose: Meaningless in MCP (no console output)\n * - silent: Meaningless in MCP\n * - configPath: Always use default path from process.cwd()\n * - delete: Not applicable to import\n * - simulateCommands/simulateSubagents/simulateSkills: Not applicable to import\n */\nexport const importOptionsSchema = z.object({\n target: z.string(),\n features: z.optional(z.array(z.string())),\n global: z.optional(z.boolean()),\n});\n\nexport type ImportOptions = z.infer<typeof importOptionsSchema>;\n\nexport type McpImportResult = {\n success: boolean;\n result?: McpResultCounts;\n config?: {\n target: string;\n features: string[];\n global: boolean;\n };\n error?: string;\n};\n\n/**\n * Execute the rulesync import command via MCP\n * Configuration priority: MCP Parameters > rulesync.local.jsonc > rulesync.jsonc > Default values\n */\nexport async function executeImport(options: ImportOptions): Promise<McpImportResult> {\n try {\n // Validate target\n if (!options.target) {\n return {\n success: false,\n error: \"target is required. Please specify a tool to import from.\",\n };\n }\n\n // Resolve config with MCP parameters taking precedence\n // ConfigResolver handles: CLI options > rulesync.local.jsonc > rulesync.jsonc > defaults\n // In MCP context, options act as CLI options (highest priority)\n const config = await ConfigResolver.resolve({\n targets: [options.target] as RulesyncTargets,\n features: options.features as RulesyncFeatures | undefined,\n global: options.global,\n // Always use default outputRoots (process.cwd()) and configPath\n // verbose and silent are meaningless in MCP context\n verbose: false,\n silent: true,\n });\n\n const tool = config.getTargets()[0] as ToolTarget;\n\n const logger = new ConsoleLogger({ verbose: false, silent: true });\n const importResult = await importFromTool({ config, tool, logger });\n\n return buildSuccessResponse({ importResult, config, tool });\n } catch (error) {\n return {\n success: false,\n error: formatError(error),\n };\n }\n}\n\nfunction buildSuccessResponse(params: {\n importResult: ImportResult;\n config: Config;\n tool: ToolTarget;\n}): McpImportResult {\n const { importResult, config, tool } = params;\n\n const totalCount = calculateTotalCount(importResult);\n\n return {\n success: true,\n result: {\n rulesCount: importResult.rulesCount,\n ignoreCount: importResult.ignoreCount,\n mcpCount: importResult.mcpCount,\n commandsCount: importResult.commandsCount,\n subagentsCount: importResult.subagentsCount,\n skillsCount: importResult.skillsCount,\n hooksCount: importResult.hooksCount,\n permissionsCount: importResult.permissionsCount,\n checksCount: importResult.checksCount,\n totalCount,\n },\n config: {\n target: tool,\n features: config.getFeatures(),\n global: config.getGlobal(),\n },\n };\n}\n\nconst importToolSchemas = {\n executeImport: importOptionsSchema,\n};\n\nexport const importTools = {\n executeImport: {\n name: \"executeImport\",\n description:\n \"Execute the rulesync import command to import configuration files from an AI tool into .rulesync directory. Requires exactly one target tool to import from.\",\n parameters: importToolSchemas.executeImport,\n execute: async (options: ImportOptions): Promise<string> => {\n const result = await executeImport(options);\n return JSON.stringify(result, null, 2);\n },\n },\n};\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_MCP_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { RulesyncMcp } from \"../features/mcp/rulesync-mcp.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, fileExists, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxMcpSizeBytes = 1024 * 1024; // 1MB\n\n/**\n * Tool to get the MCP configuration file\n */\nasync function getMcpFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n try {\n const rulesyncMcp = await RulesyncMcp.fromFile({\n validate: true,\n });\n\n const relativePathFromCwd = join(\n rulesyncMcp.getRelativeDirPath(),\n rulesyncMcp.getRelativeFilePath(),\n );\n\n return {\n relativePathFromCwd,\n content: rulesyncMcp.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to read MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the MCP configuration file (upsert operation)\n */\nasync function putMcpFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n // Check file size constraint\n if (content.length > maxMcpSizeBytes) {\n throw new Error(\n `MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB) for ${RULESYNC_MCP_RELATIVE_FILE_PATH}`,\n );\n }\n\n // Validate JSON format\n try {\n JSON.parse(content);\n } catch (error) {\n throw new Error(\n `Invalid JSON format in MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncMcp.getSettablePaths();\n\n // A .jsonc variant takes precedence at read time, so writing the .json\n // variant while it exists would be silently ignored — and rewriting the\n // .jsonc file here would destroy its comments. Refuse instead.\n const jsoncRelativePath = join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);\n if (await fileExists(join(outputRoot, jsoncRelativePath))) {\n throw new Error(\n `${jsoncRelativePath} exists and takes precedence over ${RULESYNC_MCP_RELATIVE_FILE_PATH}. Edit ${jsoncRelativePath} directly instead.`,\n );\n }\n\n // Use recommended path\n const relativeDirPath = paths.recommended.relativeDirPath;\n const relativeFilePath = paths.recommended.relativeFilePath;\n const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);\n\n // Create a RulesyncMcp instance to validate the content\n const rulesyncMcp = new RulesyncMcp({\n outputRoot,\n relativeDirPath,\n relativeFilePath,\n fileContent: content,\n validate: true,\n });\n\n // Ensure directory exists\n await ensureDir(join(outputRoot, relativeDirPath));\n\n // Write the file\n await writeFileContent(fullPath, content);\n\n const relativePathFromCwd = join(relativeDirPath, relativeFilePath);\n\n return {\n relativePathFromCwd,\n content: rulesyncMcp.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to write MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the MCP configuration file\n */\nasync function deleteMcpFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncMcp.getSettablePaths();\n\n // Try to delete both recommended and legacy paths\n const recommendedPath = join(\n outputRoot,\n paths.recommended.relativeDirPath,\n paths.recommended.relativeFilePath,\n );\n const legacyPath = join(\n outputRoot,\n paths.legacy.relativeDirPath,\n paths.legacy.relativeFilePath,\n );\n\n // Remove recommended path if it exists\n await removeFile(recommendedPath);\n\n // Remove the .jsonc variant if it exists\n await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));\n\n // Remove legacy path if it exists\n await removeFile(legacyPath);\n\n const relativePathFromCwd = join(\n paths.recommended.relativeDirPath,\n paths.recommended.relativeFilePath,\n );\n\n return {\n relativePathFromCwd,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for MCP-related tool parameters\n */\nconst mcpToolSchemas = {\n getMcpFile: z.object({}),\n putMcpFile: z.object({\n content: z.string(),\n }),\n deleteMcpFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for MCP-related operations\n */\nexport const mcpTools = {\n getMcpFile: {\n name: \"getMcpFile\",\n description: `Get the MCP configuration file (${RULESYNC_MCP_RELATIVE_FILE_PATH}).`,\n parameters: mcpToolSchemas.getMcpFile,\n execute: async () => {\n const result = await getMcpFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putMcpFile: {\n name: \"putMcpFile\",\n description:\n \"Create or update the MCP configuration file (upsert operation). content parameter is required and must be valid JSON.\",\n parameters: mcpToolSchemas.putMcpFile,\n execute: async (args: { content: string }) => {\n const result = await putMcpFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteMcpFile: {\n name: \"deleteMcpFile\",\n description: \"Delete the MCP configuration file.\",\n parameters: mcpToolSchemas.deleteMcpFile,\n execute: async () => {\n const result = await deleteMcpFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { RulesyncPermissions } from \"../features/permissions/rulesync-permissions.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, fileExists, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxPermissionsSizeBytes = 1024 * 1024; // 1MB\n\n/**\n * Tool to get the permissions configuration file\n */\nasync function getPermissionsFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n try {\n const rulesyncPermissions = await RulesyncPermissions.fromFile({\n validate: true,\n });\n\n const relativePathFromCwd = join(\n rulesyncPermissions.getRelativeDirPath(),\n rulesyncPermissions.getRelativeFilePath(),\n );\n\n return {\n relativePathFromCwd,\n content: rulesyncPermissions.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to read permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the permissions configuration file (upsert operation)\n */\nasync function putPermissionsFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n // Check file size constraint\n if (content.length > maxPermissionsSizeBytes) {\n throw new Error(\n `Permissions file size ${content.length} bytes exceeds maximum ${maxPermissionsSizeBytes} bytes (1MB) for ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}`,\n );\n }\n\n // Validate JSON format\n try {\n JSON.parse(content);\n } catch (error) {\n throw new Error(\n `Invalid JSON format in permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncPermissions.getSettablePaths();\n\n // A .jsonc variant takes precedence at read time, so writing the .json\n // variant while it exists would be silently ignored — and rewriting the\n // .jsonc file here would destroy its comments. Refuse instead.\n const jsoncRelativePath = join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);\n if (await fileExists(join(outputRoot, jsoncRelativePath))) {\n throw new Error(\n `${jsoncRelativePath} exists and takes precedence over ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}. Edit ${jsoncRelativePath} directly instead.`,\n );\n }\n\n const relativeDirPath = paths.relativeDirPath;\n const relativeFilePath = paths.relativeFilePath;\n const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);\n\n // Create a RulesyncPermissions instance to validate the content\n const rulesyncPermissions = new RulesyncPermissions({\n outputRoot,\n relativeDirPath,\n relativeFilePath,\n fileContent: content,\n validate: true,\n });\n\n // Ensure directory exists\n await ensureDir(join(outputRoot, relativeDirPath));\n\n // Write the file\n await writeFileContent(fullPath, content);\n\n const relativePathFromCwd = join(relativeDirPath, relativeFilePath);\n\n return {\n relativePathFromCwd,\n content: rulesyncPermissions.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to write permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the permissions configuration file\n */\nasync function deletePermissionsFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncPermissions.getSettablePaths();\n\n const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);\n\n await removeFile(filePath);\n\n // Remove the .jsonc variant if it exists\n await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));\n\n const relativePathFromCwd = join(paths.relativeDirPath, paths.relativeFilePath);\n\n return {\n relativePathFromCwd,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for permissions-related tool parameters\n */\nconst permissionsToolSchemas = {\n getPermissionsFile: z.object({}),\n putPermissionsFile: z.object({\n content: z.string(),\n }),\n deletePermissionsFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for permissions-related operations\n */\nexport const permissionsTools = {\n getPermissionsFile: {\n name: \"getPermissionsFile\",\n description: `Get the permissions configuration file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}).`,\n parameters: permissionsToolSchemas.getPermissionsFile,\n execute: async () => {\n const result = await getPermissionsFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putPermissionsFile: {\n name: \"putPermissionsFile\",\n description:\n \"Create or update the permissions configuration file (upsert operation). content parameter is required and must be valid JSON.\",\n parameters: permissionsToolSchemas.putPermissionsFile,\n execute: async (args: { content: string }) => {\n const result = await putPermissionsFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deletePermissionsFile: {\n name: \"deletePermissionsFile\",\n description: \"Delete the permissions configuration file.\",\n parameters: permissionsToolSchemas.deletePermissionsFile,\n execute: async () => {\n const result = await deletePermissionsFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_RULES_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncRule,\n type RulesyncRuleFrontmatter,\n type RulesyncRuleFrontmatterInput,\n RulesyncRuleFrontmatterSchema,\n} from \"../features/rules/rulesync-rule.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxRuleSizeBytes = 1024 * 1024; // 1MB\nconst maxRulesCount = 1000;\n\n/**\n * Tool to list all rules from .rulesync/rules/*.md\n */\nasync function listRules(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatter;\n }>\n> {\n const rulesDir = join(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(rulesDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const rules = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n // Read the rule file using RulesyncRule\n const rule = await RulesyncRule.fromFile({\n relativeFilePath: file,\n validate: true,\n });\n\n const frontmatter = rule.getFrontmatter();\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, file),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read rule file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return rules.filter((rule): rule is NonNullable<typeof rule> => rule !== null);\n } catch (error) {\n logger.error(\n `Failed to read rules directory (${RULESYNC_RULES_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific rule\n */\nasync function getRule({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const rule = await RulesyncRule.fromFile({\n relativeFilePath: filename,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n frontmatter: rule.getFrontmatter(),\n body: rule.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read rule file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a rule (upsert operation)\n */\nasync function putRule({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatterInput;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxRuleSizeBytes) {\n throw new Error(\n `Rule size ${estimatedSize} bytes exceeds maximum ${maxRuleSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check rule count constraint\n const existingRules = await listRules();\n const isUpdate = existingRules.some(\n (rule) => rule.relativePathFromCwd === join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingRules.length >= maxRulesCount) {\n throw new Error(\n `Maximum number of rules (${maxRulesCount}) reached in ${RULESYNC_RULES_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Create a new RulesyncRule instance\n const rule = new RulesyncRule({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n validate: true,\n });\n\n // Ensure directory exists\n const rulesDir = join(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);\n await ensureDir(rulesDir);\n\n // Write the file\n await writeFileContent(rule.getFilePath(), rule.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n frontmatter: rule.getFrontmatter(),\n body: rule.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write rule file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a rule\n */\nasync function deleteRule({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Schema for rule-related tool parameters\n */\nconst ruleToolSchemas = {\n listRules: z.object({}),\n getRule: z.object({\n relativePathFromCwd: z.string(),\n }),\n putRule: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncRuleFrontmatterSchema,\n body: z.string(),\n }),\n deleteRule: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for rule-related operations\n */\nexport const ruleTools = {\n listRules: {\n name: \"listRules\",\n description: `List all rules from ${join(RULESYNC_RULES_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: ruleToolSchemas.listRules,\n execute: async () => {\n const rules = await listRules();\n const output = { rules };\n return JSON.stringify(output, null, 2);\n },\n },\n getRule: {\n name: \"getRule\",\n description:\n \"Get detailed information about a specific rule. relativePathFromCwd parameter is required.\",\n parameters: ruleToolSchemas.getRule,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getRule({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putRule: {\n name: \"putRule\",\n description:\n \"Create or update a rule (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: ruleToolSchemas.putRule,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatterInput;\n body: string;\n }) => {\n const result = await putRule({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteRule: {\n name: \"deleteRule\",\n description: \"Delete a rule file. relativePathFromCwd parameter is required.\",\n parameters: ruleToolSchemas.deleteRule,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteRule({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, dirname, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { SKILL_FILE_NAME } from \"../constants/general.js\";\nimport { RULESYNC_SKILLS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncSkill,\n type RulesyncSkillFrontmatter,\n RulesyncSkillFrontmatterSchema,\n} from \"../features/skills/rulesync-skill.js\";\nimport { AiDirFile } from \"../types/ai-dir.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n directoryExists,\n ensureDir,\n findFilesByGlobs,\n removeDirectory,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { stringifyFrontmatter } from \"../utils/frontmatter.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxSkillSizeBytes = 1024 * 1024; // 1MB\nconst maxSkillsCount = 1000;\n\n/**\n * Type for other files in MCP API (string-based for easier AI agent use)\n */\ntype McpSkillFile = {\n name: string;\n body: string;\n};\n\n/**\n * Convert AiDirFile to McpSkillFile\n */\nfunction aiDirFileToMcpSkillFile(file: AiDirFile): McpSkillFile {\n return {\n name: file.relativeFilePathToDirPath,\n body: file.fileBuffer.toString(\"utf-8\"),\n };\n}\n\n/**\n * Convert McpSkillFile to AiDirFile\n */\nfunction mcpSkillFileToAiDirFile(file: McpSkillFile): AiDirFile {\n return {\n relativeFilePathToDirPath: file.name,\n fileBuffer: Buffer.from(file.body, \"utf-8\"),\n };\n}\n\n/**\n * Extract directory name from relative path\n * @example \".rulesync/skills/my-skill\" -> \"my-skill\"\n */\nfunction extractDirName(relativeDirPathFromCwd: string): string {\n const dirName = basename(relativeDirPathFromCwd);\n if (!dirName) {\n throw new Error(`Invalid path: ${relativeDirPathFromCwd}`);\n }\n return dirName;\n}\n\n/**\n * Tool to list all skills from .rulesync/skills/\\*\\/SKILL.md\n */\nasync function listSkills(): Promise<\n Array<{\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n }>\n> {\n const skillsDir = join(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);\n\n try {\n // Find all skill directories (directories containing SKILL.md)\n const skillDirPaths = await findFilesByGlobs(join(skillsDir, \"*\"), { type: \"dir\" });\n\n const skills = await Promise.all(\n skillDirPaths.map(async (dirPath) => {\n const dirName = basename(dirPath);\n if (!dirName) return null;\n try {\n // Read the skill using RulesyncSkill\n const skill = await RulesyncSkill.fromDir({\n dirName,\n });\n\n const frontmatter = skill.getFrontmatter();\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read skill directory ${dirName}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return skills.filter((skill): skill is NonNullable<typeof skill> => skill !== null);\n } catch (error) {\n logger.error(\n `Failed to read skills directory (${RULESYNC_SKILLS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific skill\n */\nasync function getSkill({ relativeDirPathFromCwd }: { relativeDirPathFromCwd: string }): Promise<{\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles: McpSkillFile[];\n}> {\n checkPathTraversal({\n relativePath: relativeDirPathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const dirName = extractDirName(relativeDirPathFromCwd);\n\n try {\n const skill = await RulesyncSkill.fromDir({\n dirName,\n });\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n frontmatter: skill.getFrontmatter(),\n body: skill.getBody(),\n otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile),\n };\n } catch (error) {\n throw new Error(\n `Failed to read skill directory ${relativeDirPathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update a skill (upsert operation)\n */\nasync function putSkill({\n relativeDirPathFromCwd,\n frontmatter,\n body,\n otherFiles = [],\n}: {\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles?: McpSkillFile[];\n}): Promise<{\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles: McpSkillFile[];\n}> {\n checkPathTraversal({\n relativePath: relativeDirPathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const dirName = extractDirName(relativeDirPathFromCwd);\n\n // Check file size constraint\n const estimatedSize =\n JSON.stringify(frontmatter).length +\n body.length +\n otherFiles.reduce((acc, file) => acc + file.name.length + file.body.length, 0);\n if (estimatedSize > maxSkillSizeBytes) {\n throw new Error(\n `Skill size ${estimatedSize} bytes exceeds maximum ${maxSkillSizeBytes} bytes (1MB) for ${relativeDirPathFromCwd}`,\n );\n }\n\n try {\n // Check skill count constraint\n const existingSkills = await listSkills();\n const isUpdate = existingSkills.some(\n (skill) => skill.relativeDirPathFromCwd === join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n );\n\n if (!isUpdate && existingSkills.length >= maxSkillsCount) {\n throw new Error(\n `Maximum number of skills (${maxSkillsCount}) reached in ${RULESYNC_SKILLS_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Convert McpSkillFile to AiDirFile for RulesyncSkill\n const aiDirFiles = otherFiles.map(mcpSkillFileToAiDirFile);\n\n // Create a new RulesyncSkill instance for validation\n const skill = new RulesyncSkill({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,\n dirName,\n frontmatter,\n body,\n otherFiles: aiDirFiles,\n validate: true,\n });\n\n // Ensure skill directory exists\n const skillDirPath = join(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);\n await ensureDir(skillDirPath);\n\n // Write the SKILL.md file\n const skillFilePath = join(skillDirPath, SKILL_FILE_NAME);\n const skillFileContent = stringifyFrontmatter(body, frontmatter);\n await writeFileContent(skillFilePath, skillFileContent);\n\n // Write other files\n for (const file of otherFiles) {\n // Validate file path to prevent path traversal\n checkPathTraversal({\n relativePath: file.name,\n intendedRootDir: skillDirPath,\n });\n const filePath = join(skillDirPath, file.name);\n // Ensure subdirectory exists if file has path separators\n const fileDir = join(skillDirPath, dirname(file.name));\n if (fileDir !== skillDirPath) {\n await ensureDir(fileDir);\n }\n await writeFileContent(filePath, file.body);\n }\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n frontmatter: skill.getFrontmatter(),\n body: skill.getBody(),\n otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile),\n };\n } catch (error) {\n throw new Error(\n `Failed to write skill directory ${relativeDirPathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete a skill\n */\nasync function deleteSkill({\n relativeDirPathFromCwd,\n}: {\n relativeDirPathFromCwd: string;\n}): Promise<{\n relativeDirPathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativeDirPathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const dirName = extractDirName(relativeDirPathFromCwd);\n const skillDirPath = join(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);\n\n try {\n // Check if skill directory exists before attempting to delete\n if (await directoryExists(skillDirPath)) {\n await removeDirectory(skillDirPath);\n }\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n };\n } catch (error) {\n throw new Error(\n `Failed to delete skill directory ${relativeDirPathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for other files in a skill directory\n */\nconst McpSkillFileSchema = z.object({\n name: z.string(),\n body: z.string(),\n});\n\n/**\n * Schema for skill-related tool parameters\n */\nconst skillToolSchemas = {\n listSkills: z.object({}),\n getSkill: z.object({\n relativeDirPathFromCwd: z.string(),\n }),\n putSkill: z.object({\n relativeDirPathFromCwd: z.string(),\n frontmatter: RulesyncSkillFrontmatterSchema,\n body: z.string(),\n otherFiles: z.optional(z.array(McpSkillFileSchema)),\n }),\n deleteSkill: z.object({\n relativeDirPathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for skill-related operations\n */\nexport const skillTools = {\n listSkills: {\n name: \"listSkills\",\n description: `List all skills from ${join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, \"*\", SKILL_FILE_NAME)} with their frontmatter.`,\n parameters: skillToolSchemas.listSkills,\n execute: async () => {\n const skills = await listSkills();\n const output = { skills };\n return JSON.stringify(output, null, 2);\n },\n },\n getSkill: {\n name: \"getSkill\",\n description:\n \"Get detailed information about a specific skill including SKILL.md content and other files. relativeDirPathFromCwd parameter is required.\",\n parameters: skillToolSchemas.getSkill,\n execute: async (args: { relativeDirPathFromCwd: string }) => {\n const result = await getSkill({ relativeDirPathFromCwd: args.relativeDirPathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putSkill: {\n name: \"putSkill\",\n description:\n \"Create or update a skill (upsert operation). relativeDirPathFromCwd, frontmatter, and body parameters are required. otherFiles is optional.\",\n parameters: skillToolSchemas.putSkill,\n execute: async (args: {\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles?: McpSkillFile[];\n }) => {\n const result = await putSkill({\n relativeDirPathFromCwd: args.relativeDirPathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n otherFiles: args.otherFiles,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteSkill: {\n name: \"deleteSkill\",\n description:\n \"Delete a skill directory and all its contents. relativeDirPathFromCwd parameter is required.\",\n parameters: skillToolSchemas.deleteSkill,\n execute: async (args: { relativeDirPathFromCwd: string }) => {\n const result = await deleteSkill({ relativeDirPathFromCwd: args.relativeDirPathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncSubagent,\n type RulesyncSubagentFrontmatter,\n RulesyncSubagentFrontmatterSchema,\n} from \"../features/subagents/rulesync-subagent.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxSubagentSizeBytes = 1024 * 1024; // 1MB\nconst maxSubagentsCount = 1000;\n\n/**\n * Tool to list all subagents from .rulesync/subagents/*.md\n */\nasync function listSubagents(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n }>\n> {\n const subagentsDir = join(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(subagentsDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const subagents = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n // Read the subagent file using RulesyncSubagent\n const subagent = await RulesyncSubagent.fromFile({\n relativeFilePath: file,\n validate: true,\n });\n\n const frontmatter = subagent.getFrontmatter();\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read subagent file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return subagents.filter(\n (subagent): subagent is NonNullable<typeof subagent> => subagent !== null,\n );\n } catch (error) {\n logger.error(\n `Failed to read subagents directory (${RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific subagent\n */\nasync function getSubagent({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const subagent = await RulesyncSubagent.fromFile({\n relativeFilePath: filename,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n frontmatter: subagent.getFrontmatter(),\n body: subagent.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read subagent file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a subagent (upsert operation)\n */\nasync function putSubagent({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxSubagentSizeBytes) {\n throw new Error(\n `Subagent size ${estimatedSize} bytes exceeds maximum ${maxSubagentSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check subagent count constraint\n const existingSubagents = await listSubagents();\n const isUpdate = existingSubagents.some(\n (subagent) =>\n subagent.relativePathFromCwd === join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {\n throw new Error(\n `Maximum number of subagents (${maxSubagentsCount}) reached in ${RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Create a new RulesyncSubagent instance\n const subagent = new RulesyncSubagent({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n validate: true,\n });\n\n // Ensure directory exists\n const subagentsDir = join(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);\n await ensureDir(subagentsDir);\n\n // Write the file\n await writeFileContent(subagent.getFilePath(), subagent.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n frontmatter: subagent.getFrontmatter(),\n body: subagent.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write subagent file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a subagent\n */\nasync function deleteSubagent({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(\n `Failed to delete subagent file ${relativePathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for subagent-related tool parameters\n */\nconst subagentToolSchemas = {\n listSubagents: z.object({}),\n getSubagent: z.object({\n relativePathFromCwd: z.string(),\n }),\n putSubagent: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncSubagentFrontmatterSchema,\n body: z.string(),\n }),\n deleteSubagent: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for subagent-related operations\n */\nexport const subagentTools = {\n listSubagents: {\n name: \"listSubagents\",\n description: `List all subagents from ${join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: subagentToolSchemas.listSubagents,\n execute: async () => {\n const subagents = await listSubagents();\n const output = { subagents };\n return JSON.stringify(output, null, 2);\n },\n },\n getSubagent: {\n name: \"getSubagent\",\n description:\n \"Get detailed information about a specific subagent. relativePathFromCwd parameter is required.\",\n parameters: subagentToolSchemas.getSubagent,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getSubagent({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putSubagent: {\n name: \"putSubagent\",\n description:\n \"Create or update a subagent (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: subagentToolSchemas.putSubagent,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n }) => {\n const result = await putSubagent({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteSubagent: {\n name: \"deleteSubagent\",\n description: \"Delete a subagent file. relativePathFromCwd parameter is required.\",\n parameters: subagentToolSchemas.deleteSubagent,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteSubagent({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { z } from \"zod/mini\";\n\nimport {\n type RulesyncCheckFrontmatter,\n RulesyncCheckFrontmatterSchema,\n} from \"../features/checks/rulesync-check.js\";\nimport {\n type RulesyncCommandFrontmatter,\n RulesyncCommandFrontmatterSchema,\n} from \"../features/commands/rulesync-command.js\";\nimport {\n type RulesyncRuleFrontmatter,\n RulesyncRuleFrontmatterSchema,\n} from \"../features/rules/rulesync-rule.js\";\nimport {\n type RulesyncSkillFrontmatter,\n RulesyncSkillFrontmatterSchema,\n} from \"../features/skills/rulesync-skill.js\";\nimport {\n type RulesyncSubagentFrontmatter,\n RulesyncSubagentFrontmatterSchema,\n} from \"../features/subagents/rulesync-subagent.js\";\nimport { checkTools } from \"./checks.js\";\nimport { commandTools } from \"./commands.js\";\nimport { convertOptionsSchema, convertTools } from \"./convert.js\";\nimport { generateOptionsSchema, generateTools } from \"./generate.js\";\nimport { hooksTools } from \"./hooks.js\";\nimport { ignoreTools } from \"./ignore.js\";\nimport { importOptionsSchema, importTools } from \"./import.js\";\nimport { mcpTools } from \"./mcp.js\";\nimport { permissionsTools } from \"./permissions.js\";\nimport { ruleTools } from \"./rules.js\";\nimport { skillTools } from \"./skills.js\";\nimport { subagentTools } from \"./subagents.js\";\n\nconst rulesyncFeatureSchema = z.enum([\n \"rule\",\n \"command\",\n \"subagent\",\n \"skill\",\n \"check\",\n \"ignore\",\n \"mcp\",\n \"permissions\",\n \"hooks\",\n \"generate\",\n \"import\",\n \"convert\",\n]);\n\nconst rulesyncOperationSchema = z.enum([\"list\", \"get\", \"put\", \"delete\", \"run\"]);\n\nconst skillFileSchema = z.object({\n name: z.string(),\n body: z.string(),\n});\n\nconst rulesyncToolSchema = z.object({\n feature: rulesyncFeatureSchema,\n operation: rulesyncOperationSchema,\n targetPathFromCwd: z.optional(z.string()),\n frontmatter: z.optional(z.unknown()),\n body: z.optional(z.string()),\n otherFiles: z.optional(z.array(skillFileSchema)),\n content: z.optional(z.string()),\n generateOptions: z.optional(generateOptionsSchema),\n importOptions: z.optional(importOptionsSchema),\n convertOptions: z.optional(convertOptionsSchema),\n});\n\ntype RulesyncFeature = z.infer<typeof rulesyncFeatureSchema>;\ntype RulesyncOperation = z.infer<typeof rulesyncOperationSchema>;\ntype RulesyncToolArgs = z.infer<typeof rulesyncToolSchema>;\ntype RulesyncFrontmatterFeature = Exclude<\n RulesyncFeature,\n \"ignore\" | \"mcp\" | \"permissions\" | \"hooks\" | \"generate\" | \"import\" | \"convert\"\n>;\ntype RulesyncFrontmatterByFeature = {\n rule: RulesyncRuleFrontmatter;\n command: RulesyncCommandFrontmatter;\n subagent: RulesyncSubagentFrontmatter;\n skill: RulesyncSkillFrontmatter;\n check: RulesyncCheckFrontmatter;\n};\n\nconst supportedOperationsByFeature: Record<RulesyncFeature, RulesyncOperation[]> = {\n rule: [\"list\", \"get\", \"put\", \"delete\"],\n command: [\"list\", \"get\", \"put\", \"delete\"],\n subagent: [\"list\", \"get\", \"put\", \"delete\"],\n skill: [\"list\", \"get\", \"put\", \"delete\"],\n check: [\"list\", \"get\", \"put\", \"delete\"],\n ignore: [\"get\", \"put\", \"delete\"],\n mcp: [\"get\", \"put\", \"delete\"],\n permissions: [\"get\", \"put\", \"delete\"],\n hooks: [\"get\", \"put\", \"delete\"],\n generate: [\"run\"],\n import: [\"run\"],\n convert: [\"run\"],\n};\n\nfunction assertSupported({\n feature,\n operation,\n}: {\n feature: RulesyncFeature;\n operation: RulesyncOperation;\n}): void {\n const supportedOperations = supportedOperationsByFeature[feature];\n\n if (!supportedOperations.includes(operation)) {\n throw new Error(\n `Operation ${operation} is not supported for feature ${feature}. Supported operations: ${supportedOperations.join(\n \", \",\n )}`,\n );\n }\n}\n\nfunction requireTargetPath({ targetPathFromCwd, feature, operation }: RulesyncToolArgs): string {\n if (!targetPathFromCwd) {\n throw new Error(`targetPathFromCwd is required for ${feature} ${operation} operation`);\n }\n\n return targetPathFromCwd;\n}\n\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"rule\";\n frontmatter: unknown;\n}): RulesyncRuleFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"command\";\n frontmatter: unknown;\n}): RulesyncCommandFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"subagent\";\n frontmatter: unknown;\n}): RulesyncSubagentFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"skill\";\n frontmatter: unknown;\n}): RulesyncSkillFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"check\";\n frontmatter: unknown;\n}): RulesyncCheckFrontmatter;\nfunction parseFrontmatter<Feature extends RulesyncFrontmatterFeature>({\n feature,\n frontmatter,\n}: {\n feature: Feature;\n frontmatter: unknown;\n}): RulesyncFrontmatterByFeature[Feature];\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: RulesyncFrontmatterFeature;\n frontmatter: unknown;\n}): RulesyncFrontmatterByFeature[RulesyncFrontmatterFeature] {\n switch (feature) {\n case \"rule\": {\n return RulesyncRuleFrontmatterSchema.parse(frontmatter);\n }\n case \"command\": {\n return RulesyncCommandFrontmatterSchema.parse(frontmatter);\n }\n case \"subagent\": {\n return RulesyncSubagentFrontmatterSchema.parse(frontmatter);\n }\n case \"skill\": {\n return RulesyncSkillFrontmatterSchema.parse(frontmatter);\n }\n case \"check\": {\n return RulesyncCheckFrontmatterSchema.parse(frontmatter);\n }\n }\n}\n\nfunction ensureBody({ body, feature, operation }: RulesyncToolArgs): string {\n if (!body) {\n throw new Error(`body is required for ${feature} ${operation} operation`);\n }\n\n return body;\n}\n\nfunction requireContent({\n content,\n feature,\n}: {\n content: string | undefined;\n feature: string;\n}): string {\n if (!content) {\n throw new Error(`content is required for ${feature} put operation`);\n }\n\n return content;\n}\n\nfunction executeRule(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return ruleTools.listRules.execute();\n }\n\n if (parsed.operation === \"get\") {\n return ruleTools.getRule.execute({ relativePathFromCwd: requireTargetPath(parsed) });\n }\n\n if (parsed.operation === \"put\") {\n return ruleTools.putRule.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"rule\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return ruleTools.deleteRule.execute({ relativePathFromCwd: requireTargetPath(parsed) });\n}\n\nfunction executeCommand(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return commandTools.listCommands.execute();\n }\n\n if (parsed.operation === \"get\") {\n return commandTools.getCommand.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n }\n\n if (parsed.operation === \"put\") {\n return commandTools.putCommand.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"command\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return commandTools.deleteCommand.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeSubagent(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return subagentTools.listSubagents.execute();\n }\n\n if (parsed.operation === \"get\") {\n return subagentTools.getSubagent.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n }\n\n if (parsed.operation === \"put\") {\n return subagentTools.putSubagent.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"subagent\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return subagentTools.deleteSubagent.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeSkill(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return skillTools.listSkills.execute();\n }\n\n if (parsed.operation === \"get\") {\n return skillTools.getSkill.execute({ relativeDirPathFromCwd: requireTargetPath(parsed) });\n }\n\n if (parsed.operation === \"put\") {\n return skillTools.putSkill.execute({\n relativeDirPathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"skill\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n otherFiles: parsed.otherFiles ?? [],\n });\n }\n\n return skillTools.deleteSkill.execute({\n relativeDirPathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeCheck(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return checkTools.listChecks.execute();\n }\n\n if (parsed.operation === \"get\") {\n return checkTools.getCheck.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n }\n\n if (parsed.operation === \"put\") {\n return checkTools.putCheck.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"check\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return checkTools.deleteCheck.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeIgnore(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return ignoreTools.getIgnoreFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return ignoreTools.putIgnoreFile.execute({\n content: requireContent({ content: parsed.content, feature: \"ignore\" }),\n });\n }\n\n return ignoreTools.deleteIgnoreFile.execute();\n}\n\nfunction executeMcp(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return mcpTools.getMcpFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return mcpTools.putMcpFile.execute({\n content: requireContent({ content: parsed.content, feature: \"mcp\" }),\n });\n }\n\n return mcpTools.deleteMcpFile.execute();\n}\n\nfunction executePermissions(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return permissionsTools.getPermissionsFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return permissionsTools.putPermissionsFile.execute({\n content: requireContent({ content: parsed.content, feature: \"permissions\" }),\n });\n }\n\n return permissionsTools.deletePermissionsFile.execute();\n}\n\nfunction executeHooks(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return hooksTools.getHooksFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return hooksTools.putHooksFile.execute({\n content: requireContent({ content: parsed.content, feature: \"hooks\" }),\n });\n }\n\n return hooksTools.deleteHooksFile.execute();\n}\n\nfunction executeGenerate(parsed: RulesyncToolArgs) {\n // Only \"run\" operation is supported for generate feature\n return generateTools.executeGenerate.execute(parsed.generateOptions ?? {});\n}\n\nfunction executeImport(parsed: RulesyncToolArgs) {\n // Only \"run\" operation is supported for import feature\n if (!parsed.importOptions) {\n throw new Error(\"importOptions is required for import feature\");\n }\n return importTools.executeImport.execute(parsed.importOptions);\n}\n\nfunction executeConvert(parsed: RulesyncToolArgs) {\n // Only \"run\" operation is supported for convert feature\n if (!parsed.convertOptions) {\n throw new Error(\"convertOptions is required for convert feature\");\n }\n return convertTools.executeConvert.execute(parsed.convertOptions);\n}\n\nconst featureExecutors: Record<RulesyncFeature, (parsed: RulesyncToolArgs) => Promise<string>> = {\n rule: executeRule,\n command: executeCommand,\n subagent: executeSubagent,\n skill: executeSkill,\n check: executeCheck,\n ignore: executeIgnore,\n mcp: executeMcp,\n permissions: executePermissions,\n hooks: executeHooks,\n generate: executeGenerate,\n import: executeImport,\n convert: executeConvert,\n};\n\nexport const rulesyncTool = {\n name: \"rulesyncTool\",\n description:\n \"Manage Rulesync files through a single MCP tool. Features: rule/command/subagent/skill/check support list/get/put/delete; ignore/mcp/permissions/hooks support get/put/delete only; generate supports run only; import supports run only; convert supports run only. Parameters: list requires no targetPathFromCwd (lists all items); get/delete require targetPathFromCwd; put requires targetPathFromCwd, frontmatter, and body (or content for ignore/mcp/permissions/hooks); generate/run uses generateOptions to configure generation; import/run uses importOptions to configure import; convert/run uses convertOptions to configure conversion.\",\n parameters: rulesyncToolSchema,\n execute: async (args: RulesyncToolArgs) => {\n const parsed = rulesyncToolSchema.parse(args);\n\n assertSupported({ feature: parsed.feature, operation: parsed.operation });\n\n const executor = featureExecutors[parsed.feature];\n if (!executor) {\n throw new Error(`Unknown feature: ${parsed.feature}`);\n }\n\n return executor(parsed);\n },\n} as const;\n","import { FastMCP } from \"fastmcp\";\n\nimport { rulesyncTool } from \"../../mcp/tools.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\n/**\n * MCP command that starts the MCP server\n */\nexport async function mcpCommand(logger: Logger, { version }: { version: string }): Promise<void> {\n const server = new FastMCP({\n name: \"Rulesync MCP Server\",\n version: version as `${number}.${number}.${number}`,\n instructions:\n \"This server handles Rulesync files including rules, commands, MCP, ignore files, subagents and skills for any AI agents. It should be used when you need those files.\",\n });\n\n server.addTool(rulesyncTool);\n\n // Start server with stdio transport (for spawned processes)\n logger.info(\"Rulesync MCP server started via stdio\");\n\n // Start the server - this blocks execution and runs the MCP server\n // The void operator explicitly marks this as intentionally not awaited\n void server.start({\n transportType: \"stdio\",\n });\n}\n","import { join } from \"node:path\";\n\nimport { ConfigResolver } from \"../../config/config-resolver.js\";\nimport {\n RULESYNC_CONFIG_RELATIVE_FILE_PATH,\n RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH,\n} from \"../../constants/rulesync-paths.js\";\nimport { fileExists } from \"../../utils/file.js\";\n\nexport type ResolveGitignoreTargetsParams = {\n readonly cliTargets: readonly string[] | undefined;\n readonly cwd?: string;\n};\n\n/**\n * Resolve the list of targets to pass to `gitignoreCommand`.\n *\n * Precedence:\n * 1. Explicit `--targets` CLI option wins.\n * 2. If neither rulesync.jsonc nor rulesync.local.jsonc exists, return\n * `undefined` so all supported tools' entries are emitted. Otherwise a\n * user without a config file would silently get only the default\n * `[\"agentsmd\"]` target, which is a surprising behavior change.\n * 3. If `gitignoreTargetsOnly` is true (the default), return the config's\n * `targets` with `agentsmd` always appended. `AGENTS.md` is a de facto\n * standard file read by many AI tools regardless of which targets the\n * user selected, so its gitignore entries must always be emitted to\n * prevent accidental commits of generated rule files.\n * 4. Otherwise return `undefined` to emit entries for every supported tool.\n */\nexport const resolveGitignoreTargets = async ({\n cliTargets,\n cwd = process.cwd(),\n}: ResolveGitignoreTargetsParams): Promise<readonly string[] | undefined> => {\n if (cliTargets !== undefined) {\n return cliTargets;\n }\n\n const baseConfigPath = join(cwd, RULESYNC_CONFIG_RELATIVE_FILE_PATH);\n const localConfigPath = join(cwd, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);\n const [hasBase, hasLocal] = await Promise.all([\n fileExists(baseConfigPath),\n fileExists(localConfigPath),\n ]);\n\n if (!hasBase && !hasLocal) {\n return undefined;\n }\n\n const config = await ConfigResolver.resolve({});\n if (config.getGitignoreTargetsOnly()) {\n const targets = config.getTargets();\n if (targets.includes(\"agentsmd\")) {\n return targets;\n }\n return [...targets, \"agentsmd\"];\n }\n return undefined;\n};\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { Readable, Transform } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\n\nimport type { GitHubRelease, GitHubReleaseAsset } from \"../types/fetch.js\";\nimport { GitHubClient } from \"./github-client.js\";\n\nconst RULESYNC_REPO_OWNER = \"dyoshikawa\";\nconst RULESYNC_REPO_NAME = \"rulesync\";\n\n/**\n * GitHub releases URL for manual download instructions\n */\nconst RELEASES_URL = `https://github.com/${RULESYNC_REPO_OWNER}/${RULESYNC_REPO_NAME}/releases`;\n\n/**\n * Maximum download size (500MB) to prevent memory exhaustion\n */\nconst MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;\n\n/**\n * Allowed domains for downloading release assets\n */\nconst ALLOWED_DOWNLOAD_DOMAINS = [\n \"github.com\",\n \"objects.githubusercontent.com\",\n \"github-releases.githubusercontent.com\",\n \"release-assets.githubusercontent.com\",\n];\n\n/**\n * Execution environment types for rulesync\n */\nexport type ExecutionEnvironment = \"single-binary\" | \"homebrew\" | \"npm\";\n\n/**\n * Update check result\n */\nexport type UpdateCheckResult = {\n currentVersion: string;\n latestVersion: string;\n hasUpdate: boolean;\n release: GitHubRelease;\n};\n\n/**\n * Custom error for permission issues during update\n */\nexport class UpdatePermissionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"UpdatePermissionError\";\n }\n}\n\n/**\n * Detect the execution environment of rulesync.\n *\n * Uses process.execPath (the Node.js/Bun binary) and process.argv[1] (the script being executed)\n * to determine how rulesync was installed.\n */\nexport function detectExecutionEnvironment(): ExecutionEnvironment {\n const execPath = process.execPath;\n const scriptPath = process.argv[1] ?? \"\";\n\n // Single binary detection: the executable itself is named rulesync\n const isRulesyncBinary = /rulesync(-[a-z0-9]+(-[a-z0-9]+)?)?(\\.exe)?$/i.test(execPath);\n if (isRulesyncBinary) {\n // Check if the rulesync binary itself is in a Homebrew path\n if (execPath.includes(\"/homebrew/\") || execPath.includes(\"/Cellar/\")) {\n return \"homebrew\";\n }\n return \"single-binary\";\n }\n\n // Homebrew detection via script path: e.g. /opt/homebrew/lib/node_modules/rulesync/...\n if (\n (scriptPath.includes(\"/homebrew/\") || scriptPath.includes(\"/Cellar/\")) &&\n scriptPath.includes(\"rulesync\")\n ) {\n return \"homebrew\";\n }\n\n return \"npm\";\n}\n\n/**\n * Get the asset name for the current platform\n */\nexport function getPlatformAssetName(): string | null {\n const platform = os.platform();\n const arch = os.arch();\n\n // Map Node.js platform/arch to asset names\n const platformMap: Record<string, string> = {\n darwin: \"darwin\",\n linux: \"linux\",\n win32: \"windows\",\n };\n\n const archMap: Record<string, string> = {\n x64: \"x64\",\n arm64: \"arm64\",\n };\n\n const platformName = platformMap[platform];\n const archName = archMap[arch];\n\n if (!platformName || !archName) {\n return null;\n }\n\n const extension = platform === \"win32\" ? \".exe\" : \"\";\n return `rulesync-${platformName}-${archName}${extension}`;\n}\n\n/**\n * Normalize version string by removing leading 'v' and stripping pre-release suffix\n */\nexport function normalizeVersion(v: string): string {\n // Remove leading 'v' and strip pre-release suffix (e.g., \"1.2.3-beta.1\" -> \"1.2.3\")\n return v.replace(/^v/, \"\").replace(/-.*$/, \"\");\n}\n\n/**\n * Compare semantic versions\n * Returns: 1 if a > b, -1 if a < b, 0 if equal\n */\nexport function compareVersions(a: string, b: string): number {\n const aParts = normalizeVersion(a).split(\".\").map(Number);\n const bParts = normalizeVersion(b).split(\".\").map(Number);\n\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const aNum = aParts[i] ?? 0;\n const bNum = bParts[i] ?? 0;\n if (!Number.isFinite(aNum) || !Number.isFinite(bNum)) {\n throw new Error(`Invalid version format: cannot compare \"${a}\" and \"${b}\"`);\n }\n if (aNum > bNum) return 1;\n if (aNum < bNum) return -1;\n }\n return 0;\n}\n\n/**\n * Validate that a download URL is safe (HTTPS + allowed GitHub domain + repo path for github.com)\n */\nexport function validateDownloadUrl(url: string): void {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(`Invalid download URL: ${url}`);\n }\n\n if (parsed.protocol !== \"https:\") {\n throw new Error(`Download URL must use HTTPS: ${url}`);\n }\n\n const isAllowed = ALLOWED_DOWNLOAD_DOMAINS.some((domain) => parsed.hostname === domain);\n if (!isAllowed) {\n throw new Error(\n `Download URL domain \"${parsed.hostname}\" is not in the allowed list: ${ALLOWED_DOWNLOAD_DOMAINS.join(\", \")}`,\n );\n }\n\n // For github.com URLs, validate the path starts with the expected repo\n if (parsed.hostname === \"github.com\") {\n const expectedPrefix = `/${RULESYNC_REPO_OWNER}/${RULESYNC_REPO_NAME}/`;\n if (!parsed.pathname.startsWith(expectedPrefix)) {\n throw new Error(\n `Download URL path must belong to ${RULESYNC_REPO_OWNER}/${RULESYNC_REPO_NAME}: ${url}`,\n );\n }\n }\n}\n\n/**\n * Check for updates\n */\nexport async function checkForUpdate(\n currentVersion: string,\n token?: string,\n): Promise<UpdateCheckResult> {\n const client = new GitHubClient({\n token: GitHubClient.resolveToken(token),\n });\n\n const release = await client.getLatestRelease(RULESYNC_REPO_OWNER, RULESYNC_REPO_NAME);\n const latestVersion = normalizeVersion(release.tag_name);\n const normalizedCurrentVersion = normalizeVersion(currentVersion);\n\n return {\n currentVersion: normalizedCurrentVersion,\n latestVersion,\n hasUpdate: compareVersions(latestVersion, normalizedCurrentVersion) > 0,\n release,\n };\n}\n\n/**\n * Find asset by name in release\n */\nfunction findAsset(release: GitHubRelease, assetName: string): GitHubReleaseAsset | null {\n return release.assets.find((asset) => asset.name === assetName) ?? null;\n}\n\n/**\n * Download a file from URL to a destination path using streaming to limit memory usage.\n * Validates both the initial URL and the final URL after redirects.\n */\nasync function downloadFile(url: string, destPath: string): Promise<void> {\n validateDownloadUrl(url);\n\n const response = await fetch(url, {\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new Error(`Failed to download ${url}: HTTP ${response.status}`);\n }\n\n // Validate the final URL after redirects to prevent redirect-based bypass\n if (response.url) {\n validateDownloadUrl(response.url);\n }\n\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength && Number(contentLength) > MAX_DOWNLOAD_SIZE) {\n throw new Error(\n `Download too large: ${contentLength} bytes exceeds limit of ${MAX_DOWNLOAD_SIZE} bytes`,\n );\n }\n\n if (!response.body) {\n throw new Error(\"Response body is empty\");\n }\n\n // Stream the response to file with a size limit check\n const fileStream = fs.createWriteStream(destPath);\n let downloadedBytes = 0;\n\n const bodyReader = Readable.fromWeb(response.body as import(\"node:stream/web\").ReadableStream);\n\n const sizeChecker = new Transform({\n transform(chunk, _encoding, callback) {\n downloadedBytes += (chunk as Buffer).length;\n if (downloadedBytes > MAX_DOWNLOAD_SIZE) {\n callback(\n new Error(\n `Download too large: exceeded limit of ${MAX_DOWNLOAD_SIZE} bytes during streaming`,\n ),\n );\n return;\n }\n callback(null, chunk);\n },\n });\n\n await pipeline(bodyReader, sizeChecker, fileStream);\n}\n\n/**\n * Calculate SHA256 checksum of a file\n */\nasync function calculateSha256(filePath: string): Promise<string> {\n const content = await fs.promises.readFile(filePath);\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/**\n * Parse SHA256SUMS file content\n */\nexport function parseSha256Sums(content: string): Map<string, string> {\n const result = new Map<string, string>();\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n // Format: \"hash filename\" (two spaces between hash and filename)\n const match = /^([a-f0-9]{64})\\s+(.+)$/.exec(trimmed);\n if (match && match[1] && match[2]) {\n result.set(match[2].trim(), match[1]);\n }\n }\n return result;\n}\n\n/**\n * Update options\n */\nexport type UpdateOptions = {\n force?: boolean;\n token?: string;\n};\n\n/**\n * Resolve the platform binary asset and the mandatory SHA256SUMS asset from a\n * release, throwing with manual-download guidance when either is unavailable.\n */\nfunction resolveUpdateAssets(release: GitHubRelease): {\n assetName: string;\n binaryAsset: GitHubReleaseAsset;\n checksumAsset: GitHubReleaseAsset;\n} {\n // Get platform-specific asset name\n const assetName = getPlatformAssetName();\n if (!assetName) {\n throw new Error(\n `Unsupported platform: ${os.platform()} ${os.arch()}. Please download manually from ${RELEASES_URL}`,\n );\n }\n\n // Find the binary asset\n const binaryAsset = findAsset(release, assetName);\n if (!binaryAsset) {\n throw new Error(\n `Binary for ${assetName} not found in release. Please download manually from ${RELEASES_URL}`,\n );\n }\n\n // Find the SHA256SUMS asset for verification (mandatory)\n const checksumAsset = findAsset(release, \"SHA256SUMS\");\n if (!checksumAsset) {\n throw new Error(\n `SHA256SUMS not found in release. Cannot verify download integrity. Please download manually from ${RELEASES_URL}`,\n );\n }\n\n return { assetName, binaryAsset, checksumAsset };\n}\n\n/**\n * Download the binary and SHA256SUMS into the temp directory, then verify the\n * binary's checksum. Throws when the checksum entry is missing or mismatched.\n */\nasync function downloadAndVerifyBinary(params: {\n tempDir: string;\n assetName: string;\n binaryAsset: GitHubReleaseAsset;\n checksumAsset: GitHubReleaseAsset;\n}): Promise<string> {\n const { tempDir, assetName, binaryAsset, checksumAsset } = params;\n const tempBinaryPath = path.join(tempDir, assetName);\n\n // Download the binary\n await downloadFile(binaryAsset.browser_download_url, tempBinaryPath);\n\n // Verify checksum (mandatory)\n const checksumsPath = path.join(tempDir, \"SHA256SUMS\");\n await downloadFile(checksumAsset.browser_download_url, checksumsPath);\n\n const checksumsContent = await fs.promises.readFile(checksumsPath, \"utf-8\");\n const checksums = parseSha256Sums(checksumsContent);\n const expectedChecksum = checksums.get(assetName);\n\n if (!expectedChecksum) {\n throw new Error(\n `Checksum entry for \"${assetName}\" not found in SHA256SUMS. Cannot verify download integrity.`,\n );\n }\n\n const actualChecksum = await calculateSha256(tempBinaryPath);\n if (actualChecksum !== expectedChecksum) {\n throw new Error(\n `Checksum verification failed. Expected: ${expectedChecksum}, Got: ${actualChecksum}. The download may be corrupted.`,\n );\n }\n\n return tempBinaryPath;\n}\n\n/**\n * Replace the running executable at `currentExePath` with the verified binary,\n * preferring an atomic rename and falling back to a direct cross-filesystem copy.\n */\nasync function replaceCurrentBinary(params: {\n tempBinaryPath: string;\n currentExePath: string;\n currentDir: string;\n}): Promise<void> {\n const { tempBinaryPath, currentExePath, currentDir } = params;\n // Attempt atomic replacement via rename (works when on the same filesystem)\n const tempInPlace = path.join(currentDir, `.rulesync-update-${crypto.randomUUID()}`);\n try {\n await fs.promises.copyFile(tempBinaryPath, tempInPlace);\n if (os.platform() !== \"win32\") {\n await fs.promises.chmod(tempInPlace, 0o755);\n }\n await fs.promises.rename(tempInPlace, currentExePath);\n } catch {\n // Cleanup temp-in-place file on failure, then fall back to direct copy\n try {\n await fs.promises.unlink(tempInPlace);\n } catch {\n // Ignore cleanup errors\n }\n // Fallback: direct copy (non-atomic but works across filesystems)\n await fs.promises.copyFile(tempBinaryPath, currentExePath);\n if (os.platform() !== \"win32\") {\n await fs.promises.chmod(currentExePath, 0o755);\n }\n }\n}\n\n/**\n * Install the verified binary over the current executable, backing it up first\n * and restoring from backup on failure. Returns whether the restore failed so\n * the caller can preserve the temp directory for manual recovery.\n */\nasync function installVerifiedBinary(params: {\n tempDir: string;\n tempBinaryPath: string;\n currentVersion: string;\n latestVersion: string;\n}): Promise<{ message: string; restoreFailed: boolean }> {\n const { tempDir, tempBinaryPath, currentVersion, latestVersion } = params;\n\n // Resolve symlinks to get the real executable path\n const currentExePath = await fs.promises.realpath(process.execPath);\n const currentDir = path.dirname(currentExePath);\n\n // Backup current binary to temp directory (not predictable path)\n const backupPath = path.join(tempDir, \"rulesync.backup\");\n try {\n await fs.promises.copyFile(currentExePath, backupPath);\n } catch (error) {\n if (isPermissionError(error)) {\n throw new UpdatePermissionError(\n `Permission denied: Cannot read ${currentExePath}. Try running with sudo.`,\n );\n }\n throw error;\n }\n\n try {\n await replaceCurrentBinary({ tempBinaryPath, currentExePath, currentDir });\n return {\n message: `Successfully updated from ${currentVersion} to ${latestVersion}`,\n restoreFailed: false,\n };\n } catch (error) {\n // Restore from backup on failure\n try {\n await fs.promises.copyFile(backupPath, currentExePath);\n } catch {\n throw new RestoreFailedError(\n new Error(\n `Failed to replace binary and restore failed. Backup is preserved at: ${backupPath} (in ${tempDir}). ` +\n `Please manually copy it to ${currentExePath}. Original error: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n ),\n );\n }\n if (isPermissionError(error)) {\n throw new UpdatePermissionError(\n `Permission denied: Cannot write to ${path.dirname(currentExePath)}. Try running with sudo.`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Internal marker wrapping the error thrown when both the binary replacement\n * and the backup restore fail. The caller unwraps it so the temp directory is\n * preserved for manual recovery (mirrors the original inline `restoreFailed`\n * flag behavior).\n */\nclass RestoreFailedError extends Error {\n override readonly cause: Error;\n constructor(cause: Error) {\n super(cause.message);\n this.name = \"RestoreFailedError\";\n this.cause = cause;\n }\n}\n\n/**\n * Perform the binary update\n */\nexport async function performBinaryUpdate(\n currentVersion: string,\n options: UpdateOptions = {},\n): Promise<string> {\n const { force = false, token } = options;\n\n // Check for updates\n const updateCheck = await checkForUpdate(currentVersion, token);\n\n if (!updateCheck.hasUpdate && !force) {\n return `Already at the latest version (${currentVersion})`;\n }\n\n const { assetName, binaryAsset, checksumAsset } = resolveUpdateAssets(updateCheck.release);\n\n // Create temporary directory for download\n const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), \"rulesync-update-\"));\n let restoreFailed = false;\n\n try {\n // Set restrictive permissions on temp directory (Unix only)\n if (os.platform() !== \"win32\") {\n await fs.promises.chmod(tempDir, 0o700);\n }\n\n const tempBinaryPath = await downloadAndVerifyBinary({\n tempDir,\n assetName,\n binaryAsset,\n checksumAsset,\n });\n\n const installed = await installVerifiedBinary({\n tempDir,\n tempBinaryPath,\n currentVersion,\n latestVersion: updateCheck.latestVersion,\n });\n restoreFailed = installed.restoreFailed;\n return installed.message;\n } catch (error) {\n if (error instanceof RestoreFailedError) {\n restoreFailed = true;\n throw error.cause;\n }\n throw error;\n } finally {\n // Skip cleanup if restore failed, so the backup is preserved for manual recovery\n if (!restoreFailed) {\n try {\n await fs.promises.rm(tempDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n}\n\n/**\n * Check if an error is a permission error\n */\nfunction isPermissionError(error: unknown): boolean {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n const record = error as Record<string, unknown>;\n return record[\"code\"] === \"EACCES\" || record[\"code\"] === \"EPERM\";\n }\n return false;\n}\n\n/**\n * Get upgrade instructions for npm installation\n */\nexport function getNpmUpgradeInstructions(): string {\n return `This rulesync installation was installed via npm/npx.\n\nTo upgrade, run one of the following commands:\n\n Global installation:\n npm install -g rulesync@latest\n\n Project dependency:\n npm install rulesync@latest\n\n Or use npx to always run the latest version:\n npx rulesync@latest --version`;\n}\n\n/**\n * Get upgrade instructions for Homebrew installation\n */\nexport function getHomebrewUpgradeInstructions(): string {\n return `This rulesync installation was installed via Homebrew.\n\nTo upgrade, run:\n brew upgrade rulesync`;\n}\n","import { GitHubClientError } from \"../../lib/github-client.js\";\nimport {\n UpdatePermissionError,\n checkForUpdate,\n detectExecutionEnvironment,\n getHomebrewUpgradeInstructions,\n getNpmUpgradeInstructions,\n performBinaryUpdate,\n} from \"../../lib/update.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\n/**\n * Update command options\n */\nexport type UpdateCommandOptions = {\n check?: boolean;\n force?: boolean;\n verbose?: boolean;\n silent?: boolean;\n token?: string;\n};\n\n/**\n * Update command handler\n */\nexport async function updateCommand(\n logger: Logger,\n currentVersion: string,\n options: UpdateCommandOptions,\n): Promise<void> {\n const { check = false, force = false, token } = options;\n\n try {\n const environment = detectExecutionEnvironment();\n logger.debug(`Detected environment: ${environment}`);\n\n if (environment === \"npm\") {\n logger.info(getNpmUpgradeInstructions());\n return;\n }\n\n if (environment === \"homebrew\") {\n logger.info(getHomebrewUpgradeInstructions());\n return;\n }\n\n // Single-binary mode\n if (check) {\n // Check-only mode\n logger.info(\"Checking for updates...\");\n const updateCheck = await checkForUpdate(currentVersion, token);\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"currentVersion\", updateCheck.currentVersion);\n logger.captureData(\"latestVersion\", updateCheck.latestVersion);\n logger.captureData(\"updateAvailable\", updateCheck.hasUpdate);\n logger.captureData(\n \"message\",\n updateCheck.hasUpdate\n ? `Update available: ${updateCheck.currentVersion} -> ${updateCheck.latestVersion}`\n : `Already at the latest version (${updateCheck.currentVersion})`,\n );\n }\n\n if (updateCheck.hasUpdate) {\n logger.success(\n `Update available: ${updateCheck.currentVersion} -> ${updateCheck.latestVersion}`,\n );\n } else {\n logger.info(`Already at the latest version (${updateCheck.currentVersion})`);\n }\n return;\n }\n\n // Perform update\n logger.info(\"Checking for updates...\");\n const message = await performBinaryUpdate(currentVersion, { force, token });\n logger.success(message);\n } catch (error) {\n if (error instanceof GitHubClientError) {\n // Include auth hints in error message for JSON mode\n const authHint =\n error.statusCode === 401 || error.statusCode === 403\n ? \" Tip: Set GITHUB_TOKEN or GH_TOKEN environment variable, or use `GITHUB_TOKEN=$(gh auth token) rulesync update ...`\"\n : \"\";\n throw new CLIError(\n `GitHub API Error: ${error.message}.${authHint}`,\n ErrorCodes.UPDATE_FAILED,\n );\n } else if (error instanceof UpdatePermissionError) {\n throw new CLIError(\n `${error.message} Tip: Run with elevated privileges (e.g., sudo rulesync update)`,\n ErrorCodes.UPDATE_FAILED,\n );\n }\n throw error;\n }\n}\n","import { Command } from \"commander\";\n\nimport { CLIError } from \"../types/json-output.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger, JsonLogger, Logger } from \"../utils/logger.js\";\n\nexport function createLogger({\n name,\n globalOpts,\n getVersion,\n}: {\n name: string;\n globalOpts: Record<string, unknown>;\n getVersion: () => string;\n}): Logger {\n return globalOpts.json\n ? new JsonLogger({ command: name, version: getVersion() })\n : new ConsoleLogger();\n}\n\nexport function wrapCommand({\n name,\n errorCode,\n handler,\n getVersion,\n loggerFactory = createLogger,\n}: {\n name: string;\n errorCode: string;\n handler: (\n logger: Logger,\n options: unknown,\n globalOpts: Record<string, unknown>,\n positionalArgs: unknown[],\n ) => Promise<void>;\n getVersion: () => string;\n loggerFactory?: (params: {\n name: string;\n globalOpts: Record<string, unknown>;\n getVersion: () => string;\n }) => Logger;\n}) {\n return async (...args: unknown[]) => {\n // Commander passes variable args based on command signature:\n // - No positional: (options, command)\n // - With positional: (arg1, arg2, ..., options, command)\n // The last two are always (options, command)\n const command = args[args.length - 1] as Command;\n const options = args[args.length - 2] as Record<string, unknown>;\n const positionalArgs = args.slice(0, -2);\n const globalOpts = command.parent?.opts() ?? {};\n const logger = loggerFactory({ name, globalOpts, getVersion });\n logger.configure({\n verbose: Boolean(globalOpts.verbose) || Boolean(options.verbose),\n silent: Boolean(globalOpts.silent) || Boolean(options.silent),\n });\n\n try {\n await handler(logger, options, globalOpts, positionalArgs);\n logger.outputJson(true);\n } catch (error) {\n const code = error instanceof CLIError ? error.code : errorCode;\n const errorArg = error instanceof Error ? error : formatError(error);\n logger.error(errorArg, code);\n process.exit(error instanceof CLIError ? error.exitCode : 1);\n }\n };\n}\n","#!/usr/bin/env node\n\nimport { Command } from \"commander\";\n\nimport { ALL_FEATURES, RulesyncFeatures } from \"../types/features.js\";\nimport { FetchOptions } from \"../types/fetch.js\";\nimport { formatError } from \"../utils/error.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { parseCommaSeparatedList } from \"../utils/parse-comma-separated-list.js\";\nimport { convertCommand, ConvertOptions } from \"./commands/convert.js\";\nimport { fetchCommand } from \"./commands/fetch.js\";\nimport { generateCommand, GenerateOptions } from \"./commands/generate.js\";\nimport { gitignoreCommand } from \"./commands/gitignore.js\";\nimport { importCommand, ImportOptions } from \"./commands/import.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { INSTALL_MODES, InstallMode, installCommand } from \"./commands/install.js\";\nimport { mcpCommand } from \"./commands/mcp.js\";\nimport { resolveGitignoreTargets } from \"./commands/resolve-gitignore-targets.js\";\nimport { updateCommand, UpdateCommandOptions } from \"./commands/update.js\";\nimport { wrapCommand as _wrapCommand } from \"./wrap-command.js\";\n\nconst getVersion = () => \"13.0.0\";\n\nfunction wrapCommand(\n name: string,\n errorCode: string,\n handler: (\n logger: Logger,\n options: unknown,\n globalOpts: Record<string, unknown>,\n positionalArgs: unknown[],\n ) => Promise<void>,\n) {\n return _wrapCommand({ name, errorCode, handler, getVersion });\n}\n\nconst main = async () => {\n const program = new Command();\n\n const version = getVersion();\n\n program\n .name(\"rulesync\")\n .description(\"Unified AI rules management CLI tool\")\n .version(version, \"-v, --version\", \"Show version\")\n .option(\"-j, --json\", \"Output results as JSON\");\n\n program\n .command(\"init\")\n .description(\"Initialize rulesync in current directory\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"init\", \"INIT_FAILED\", async (logger) => {\n await initCommand(logger);\n }),\n );\n\n program\n .command(\"gitignore\")\n .description(\"Add generated files to .gitignore\")\n .option(\n \"-t, --targets <tools>\",\n \"Comma-separated list of tools to include (e.g., 'claudecode,copilot' or '*' for all)\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to include (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"gitignore\", \"GITIGNORE_FAILED\", async (logger, options) => {\n const cliTargets = (options as { targets?: string[] }).targets;\n const cliFeatures = (options as { features?: RulesyncFeatures }).features;\n\n const resolvedTargets = await resolveGitignoreTargets({ cliTargets });\n\n await gitignoreCommand(logger, {\n targets: resolvedTargets ? [...resolvedTargets] : undefined,\n features: cliFeatures,\n });\n }),\n );\n\n program\n .command(\"fetch <source>\")\n .description(\"Fetch files from a Git repository (GitHub/GitLab)\")\n .option(\n \"-t, --target <target>\",\n \"Target format to interpret files as (e.g., 'rulesync', 'claudecode'). Default: rulesync\",\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to fetch (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-r, --ref <ref>\", \"Branch, tag, or commit SHA to fetch from\")\n .option(\"-p, --path <path>\", \"Subdirectory path within the repository\")\n .option(\"-o, --output <dir>\", \"Output directory (default: .rulesync)\")\n .option(\n \"-c, --conflict <strategy>\",\n \"Conflict resolution strategy: skip, overwrite (default: overwrite)\",\n )\n .option(\"--token <token>\", \"Git provider token for private repositories\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"fetch\", \"FETCH_FAILED\", async (logger, options, _globalOpts, positionalArgs) => {\n const source = positionalArgs[0] as string;\n await fetchCommand(logger, { ...(options as FetchOptions), source });\n }),\n );\n\n program\n .command(\"import\")\n .description(\"Import configurations from AI tools to rulesync format\")\n .option(\n \"-t, --targets <tool>\",\n \"Tool to import from (e.g., 'copilot', 'cursor', 'cline')\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to import (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .option(\"-g, --global\", \"Import for global(user scope) configuration files\")\n .action(\n wrapCommand(\"import\", \"IMPORT_FAILED\", async (logger, options) => {\n await importCommand(logger, options as ImportOptions);\n }),\n );\n\n program\n .command(\"convert\")\n .description(\n \"Convert configurations from one AI tool to other AI tools without writing .rulesync/ files\",\n )\n .requiredOption(\"--from <tool>\", \"Source tool to convert from (e.g., 'cursor', 'claudecode')\")\n .requiredOption(\n \"--to <tools>\",\n \"Comma-separated list of destination tools (e.g., 'copilot,claudecode')\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to convert (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .option(\"-g, --global\", \"Convert for global(user scope) configuration files\")\n .option(\"--dry-run\", \"Dry run: show changes without writing files\")\n .action(\n wrapCommand(\"convert\", \"CONVERT_FAILED\", async (logger, options) => {\n await convertCommand(logger, options as ConvertOptions);\n }),\n );\n\n program\n .command(\"mcp\")\n .description(\"Start MCP server for rulesync\")\n .action(\n wrapCommand(\"mcp\", \"MCP_FAILED\", async (logger, _options) => {\n await mcpCommand(logger, { version });\n }),\n );\n\n program\n .command(\"install\")\n .description(\"Install skills/primitives from declarative sources (rulesync.jsonc) or apm.yml\")\n .option(\n \"--mode <mode>\",\n `Install layout to produce (${INSTALL_MODES.join(\"|\")}). Default: rulesync`,\n )\n .option(\"--update\", \"Force re-resolve all source refs, ignoring lockfile\")\n .option(\n \"--frozen\",\n \"Fail if lockfile is missing or out of sync (for CI); fetches missing skills using locked refs\",\n )\n .option(\"--token <token>\", \"GitHub token for private repos\")\n .option(\"-c, --config <path>\", \"Path to configuration file\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"install\", \"INSTALL_FAILED\", async (logger, options) => {\n const rawMode = (options as { mode?: string }).mode;\n const mode = parseInstallMode(rawMode);\n await installCommand(logger, {\n mode,\n update: (options as { update?: boolean }).update,\n frozen: (options as { frozen?: boolean }).frozen,\n token: (options as { token?: string }).token,\n configPath: (options as { config?: string }).config,\n verbose: (options as { verbose?: boolean }).verbose,\n silent: (options as { silent?: boolean }).silent,\n });\n }),\n );\n\n program\n .command(\"generate\")\n .description(\"Generate configuration files for AI tools\")\n .option(\n \"-t, --targets <tools>\",\n \"Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to generate (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"--delete\", \"Delete all existing files in output directories before generating\")\n .option(\n \"-o, --output-roots <paths>\",\n \"Output root directories to generate files into (comma-separated for multiple paths)\",\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .option(\"-c, --config <path>\", \"Path to configuration file\")\n .option(\"-g, --global\", \"Generate for global(user scope) configuration files\")\n .option(\n \"--simulate-commands\",\n \"Generate simulated commands. This feature is only available for copilot, cursor and codexcli.\",\n )\n .option(\n \"--simulate-subagents\",\n \"Generate simulated subagents. This feature is only available for copilot and codexcli.\",\n )\n .option(\n \"--simulate-skills\",\n \"Generate simulated skills. This feature is only available for copilot, cursor and codexcli.\",\n )\n .option(\n \"--input-root <path>\",\n \"Path to the directory containing .rulesync/ (parent of .rulesync/)\",\n )\n .option(\"--dry-run\", \"Dry run: show changes without writing files\")\n .option(\"--check\", \"Check if files are up to date (exits with code 1 if changes needed)\")\n .action(\n wrapCommand(\"generate\", \"GENERATION_FAILED\", async (logger, options) => {\n await generateCommand(logger, options as GenerateOptions);\n }),\n );\n\n program\n .command(\"update\")\n .description(\"Update rulesync to the latest version\")\n .option(\"--check\", \"Check for updates without installing\")\n .option(\"--force\", \"Force update even if already at latest version\")\n .option(\"--token <token>\", \"GitHub token for API access\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"update\", \"UPDATE_FAILED\", async (logger, options) => {\n await updateCommand(logger, version, options as UpdateCommandOptions);\n }),\n );\n\n program.parse();\n};\n\nfunction parseInstallMode(raw: string | undefined): InstallMode | undefined {\n if (raw === undefined) return undefined;\n const match = INSTALL_MODES.find((m) => m === raw);\n if (!match) {\n throw new Error(`Invalid --mode value \"${raw}\". Expected one of: ${INSTALL_MODES.join(\", \")}.`);\n }\n return match;\n}\n\nmain().catch((error) => {\n console.error(formatError(error));\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["parseToolTarget","record","SKILL_FILE_NAME","SKILL_FILE_NAME","RULESYNC_CONTENT_HASH_REGEX","computeContentHash","RULESYNC_CONTENT_HASH_REGEX","existing","assertFrozenLockCoversSources","SKILL_FILE_NAME","logger","logger","executeConvert","buildSuccessResponse","executeGenerate","buildSuccessResponse","executeImport","logger","logger","SKILL_FILE_NAME","os","path","wrapCommand","_wrapCommand"],"sources":["../../src/utils/parse-comma-separated-list.ts","../../src/utils/result.ts","../../src/cli/commands/convert.ts","../../src/types/fetch-targets.ts","../../src/types/fetch.ts","../../src/lib/github-client.ts","../../src/lib/github-utils.ts","../../src/types/git-provider.ts","../../src/lib/source-parser.ts","../../src/lib/fetch.ts","../../src/cli/commands/fetch.ts","../../src/cli/commands/generate.ts","../../src/cli/commands/gitignore-derive.ts","../../src/cli/commands/gitignore-entries.ts","../../src/cli/commands/gitignore.ts","../../src/cli/commands/import.ts","../../src/lib/init.ts","../../src/cli/commands/init.ts","../../src/lib/apm/apm-lock.ts","../../src/lib/apm/apm-manifest.ts","../../src/lib/apm/apm-install.ts","../../src/lib/gh/gh-frontmatter.ts","../../src/lib/gh/gh-lock.ts","../../src/lib/gh/gh-paths.ts","../../src/lib/gh/gh-install.ts","../../src/lib/git-client.ts","../../src/lib/npm-client.ts","../../src/lib/npm-sources-lock.ts","../../src/lib/npm-tar.ts","../../src/lib/sources-lock.ts","../../src/lib/sources.ts","../../src/cli/commands/install.ts","../../src/mcp/checks.ts","../../src/mcp/commands.ts","../../src/mcp/convert.ts","../../src/mcp/generate.ts","../../src/mcp/hooks.ts","../../src/mcp/ignore.ts","../../src/mcp/import.ts","../../src/mcp/mcp.ts","../../src/mcp/permissions.ts","../../src/mcp/rules.ts","../../src/mcp/skills.ts","../../src/mcp/subagents.ts","../../src/mcp/tools.ts","../../src/cli/commands/mcp.ts","../../src/cli/commands/resolve-gitignore-targets.ts","../../src/lib/update.ts","../../src/cli/commands/update.ts","../../src/cli/wrap-command.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * Parses a comma-separated string into a trimmed, non-empty array of strings.\n *\n * Handles trailing commas and extra whitespace gracefully.\n *\n * @example\n * parseCommaSeparatedList(\"a, b, c\") // => [\"a\", \"b\", \"c\"]\n * parseCommaSeparatedList(\"a,,b,\") // => [\"a\", \"b\"]\n */\nexport const parseCommaSeparatedList = (value: string): string[] =>\n value\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n","/**\n * Result of writing AI files, including both count and file paths\n */\nexport type WriteResult = {\n count: number;\n paths: string[];\n};\n\n/**\n * Result of feature generation, extending WriteResult with hasDiff\n */\nexport type FeatureGenerateResult = WriteResult & { hasDiff: boolean };\n\n/**\n * Common count fields shared by ImportResult and GenerateResult\n */\nexport type CountableResult = {\n rulesCount: number;\n ignoreCount: number;\n mcpCount: number;\n commandsCount: number;\n subagentsCount: number;\n skillsCount: number;\n hooksCount: number;\n permissionsCount: number;\n checksCount: number;\n};\n\n/**\n * Calculate the total count from a result object\n */\nexport function calculateTotalCount(result: CountableResult): number {\n return (\n result.rulesCount +\n result.ignoreCount +\n result.mcpCount +\n result.commandsCount +\n result.subagentsCount +\n result.skillsCount +\n result.hooksCount +\n result.permissionsCount +\n result.checksCount\n );\n}\n","import { ConfigResolver, ConfigResolverResolveParams } from \"../../config/config-resolver.js\";\nimport { convertFromTool } from \"../../lib/convert.js\";\nimport type { RulesyncFeatures } from \"../../types/features.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport { ALL_TOOL_TARGETS, type ToolTarget, ToolTargetSchema } from \"../../types/tool-targets.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { calculateTotalCount } from \"../../utils/result.js\";\n\nexport type ConvertOptions = Omit<\n ConfigResolverResolveParams,\n \"delete\" | \"outputRoots\" | \"targets\"\n> & {\n from?: string;\n to?: string[];\n features?: RulesyncFeatures;\n};\n\nfunction parseToolTarget(value: string, label: string): ToolTarget {\n const result = ToolTargetSchema.safeParse(value);\n if (!result.success) {\n throw new CLIError(\n `Invalid ${label} tool '${value}'. Must be one of: ${ALL_TOOL_TARGETS.join(\", \")}`,\n ErrorCodes.CONVERT_FAILED,\n );\n }\n return result.data;\n}\n\nexport async function convertCommand(logger: Logger, options: ConvertOptions): Promise<void> {\n // `--from` and `--to` presence is enforced by commander's `requiredOption`\n // in `src/cli/index.ts`; here we only need to validate the tool names.\n const fromTool = parseToolTarget(options.from ?? \"\", \"source\");\n const toToolsRaw = (options.to ?? []).map((t) => parseToolTarget(t, \"destination\"));\n const toTools = Array.from(new Set(toToolsRaw));\n\n if (toTools.includes(fromTool)) {\n throw new CLIError(\n `Destination tools must not include the source tool '${fromTool}'. ` +\n `Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`,\n ErrorCodes.CONVERT_FAILED,\n );\n }\n\n // Pass both source and destinations as `targets` so per-target feature maps\n // in `rulesync.jsonc` are honored for every tool involved. Default features\n // to `*` so every feature that both tools support is attempted.\n const config = await ConfigResolver.resolve({\n ...options,\n targets: [fromTool, ...toTools],\n features: options.features ?? [\"*\"],\n });\n\n const isPreview = config.isPreviewMode();\n const modePrefix = isPreview ? \"[DRY RUN] \" : \"\";\n\n logger.debug(`Converting files from ${fromTool} to ${toTools.join(\", \")}...`);\n\n const result = await convertFromTool({ config, fromTool, toTools, logger });\n\n const totalConverted = calculateTotalCount(result);\n\n if (totalConverted === 0) {\n const enabledFeatures = config.getFeatures(fromTool).join(\", \");\n logger.warn(`No files converted for enabled features: ${enabledFeatures}`);\n return;\n }\n\n if (logger.jsonMode) {\n logger.captureData(\"from\", fromTool);\n logger.captureData(\"to\", toTools);\n logger.captureData(\"dryRun\", isPreview);\n logger.captureData(\"features\", {\n rules: { count: result.rulesCount },\n ignore: { count: result.ignoreCount },\n mcp: { count: result.mcpCount },\n commands: { count: result.commandsCount },\n subagents: { count: result.subagentsCount },\n skills: { count: result.skillsCount },\n hooks: { count: result.hooksCount },\n permissions: { count: result.permissionsCount },\n checks: { count: result.checksCount },\n });\n logger.captureData(\"totalFiles\", totalConverted);\n }\n\n const parts: string[] = [];\n if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);\n if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);\n if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);\n if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);\n if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);\n if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);\n if (result.hooksCount > 0) parts.push(`${result.hooksCount} hooks`);\n if (result.permissionsCount > 0) parts.push(`${result.permissionsCount} permissions`);\n if (result.checksCount > 0) parts.push(`${result.checksCount} checks`);\n\n const verbPhrase = isPreview ? \"Would convert\" : \"Converted\";\n const summary = `${modePrefix}${verbPhrase} ${totalConverted} file(s) total from ${fromTool} to ${toTools.join(\", \")} (${parts.join(\" + \")})`;\n\n if (isPreview) {\n logger.info(summary);\n } else {\n logger.success(summary);\n }\n}\n","import { z } from \"zod/mini\";\n\nimport { ALL_TOOL_TARGETS } from \"./tool-targets.js\";\n\n/**\n * Fetch command targets for specifying file format interpretation\n * - \"rulesync\": rulesync format with frontmatter containing targets, description, etc.\n * - Tool targets: interpreted as tool-specific format (e.g., claudecode, cursor)\n */\nconst ALL_FETCH_TARGETS = [\"rulesync\", ...ALL_TOOL_TARGETS] as const;\n\nexport const FetchTargetSchema = z.enum(ALL_FETCH_TARGETS);\n\nexport type FetchTarget = z.infer<typeof FetchTargetSchema>;\n","import { z } from \"zod/mini\";\n\nimport { ALL_FEATURES_WITH_WILDCARD } from \"./features.js\";\nimport { FetchTargetSchema } from \"./fetch-targets.js\";\nimport type { GitProvider } from \"./git-provider.js\";\n\n/**\n * Conflict resolution strategies for fetch command\n */\nconst ConflictStrategySchema = z.enum([\"skip\", \"overwrite\"]);\nexport type ConflictStrategy = z.infer<typeof ConflictStrategySchema>;\n\n/**\n * GitHub file type from API response\n */\nconst GitHubFileTypeSchema = z.enum([\"file\", \"dir\", \"symlink\", \"submodule\"]);\n\n/**\n * GitHub file/directory entry from contents API\n */\nexport const GitHubFileEntrySchema = z.looseObject({\n name: z.string(),\n path: z.string(),\n sha: z.string(),\n size: z.number(),\n type: GitHubFileTypeSchema,\n download_url: z.nullable(z.string()),\n});\nexport type GitHubFileEntry = z.infer<typeof GitHubFileEntrySchema>;\n\n/**\n * Parsed source specification for fetch command\n */\nexport type ParsedSource = {\n provider: GitProvider;\n owner: string;\n repo: string;\n ref?: string;\n path?: string;\n};\n\n/**\n * Fetch command options\n */\nconst FetchOptionsSchema = z.looseObject({\n target: z.optional(FetchTargetSchema),\n features: z.optional(z.array(z.enum(ALL_FEATURES_WITH_WILDCARD))),\n ref: z.optional(z.string()),\n path: z.optional(z.string()),\n output: z.optional(z.string()),\n conflict: z.optional(ConflictStrategySchema),\n token: z.optional(z.string()),\n verbose: z.optional(z.boolean()),\n silent: z.optional(z.boolean()),\n});\nexport type FetchOptions = z.infer<typeof FetchOptionsSchema>;\n\n/**\n * Result status for a single file fetch operation\n */\nconst FetchFileStatusSchema = z.enum([\"created\", \"overwritten\", \"skipped\"]);\ntype FetchFileStatus = z.infer<typeof FetchFileStatusSchema>;\n\n/**\n * Result of a single file fetch operation\n */\nexport type FetchFileResult = {\n relativePath: string;\n status: FetchFileStatus;\n};\n\n/**\n * Summary of fetch operation\n */\nexport type FetchSummary = {\n source: string;\n ref: string;\n files: FetchFileResult[];\n created: number;\n overwritten: number;\n skipped: number;\n};\n\n/**\n * GitHub API error response\n */\nexport type GitHubApiError = {\n message: string;\n documentation_url?: string;\n};\n\n/**\n * Configuration for GitHub client\n */\nexport type GitHubClientConfig = {\n token?: string;\n baseUrl?: string;\n};\n\n/**\n * Repository information from GitHub API\n */\nexport const GitHubRepoInfoSchema = z.looseObject({\n default_branch: z.string(),\n private: z.boolean(),\n});\nexport type GitHubRepoInfo = z.infer<typeof GitHubRepoInfoSchema>;\n\n/**\n * GitHub release asset from releases API\n */\nconst GitHubReleaseAssetSchema = z.looseObject({\n name: z.string(),\n browser_download_url: z.string(),\n size: z.number(),\n});\nexport type GitHubReleaseAsset = z.infer<typeof GitHubReleaseAssetSchema>;\n\n/**\n * GitHub release from releases API\n */\nexport const GitHubReleaseSchema = z.looseObject({\n tag_name: z.string(),\n name: z.nullable(z.string()),\n prerelease: z.boolean(),\n draft: z.boolean(),\n assets: z.array(GitHubReleaseAssetSchema),\n});\nexport type GitHubRelease = z.infer<typeof GitHubReleaseSchema>;\n","import { RequestError } from \"@octokit/request-error\";\nimport { Octokit } from \"@octokit/rest\";\n\nimport { MAX_FILE_SIZE } from \"../constants/rulesync-paths.js\";\nimport type {\n GitHubApiError,\n GitHubClientConfig,\n GitHubFileEntry,\n GitHubRelease,\n GitHubRepoInfo,\n} from \"../types/fetch.js\";\nimport {\n GitHubFileEntrySchema,\n GitHubReleaseSchema,\n GitHubRepoInfoSchema,\n} from \"../types/fetch.js\";\nimport { formatError } from \"../utils/error.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/**\n * Error class for GitHub API errors\n */\nexport class GitHubClientError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly apiError?: GitHubApiError,\n ) {\n super(message);\n this.name = \"GitHubClientError\";\n }\n}\n\n/**\n * Log GitHub auth error hints for 401/403 responses.\n */\nexport function logGitHubAuthHints(params: { error: GitHubClientError; logger: Logger }): void {\n const { error, logger } = params;\n logger.error(`GitHub API Error: ${error.message}`);\n if (error.statusCode === 401 || error.statusCode === 403) {\n logger.info(\n \"Tip: Set GITHUB_TOKEN or GH_TOKEN environment variable for private repositories or better rate limits.\",\n );\n logger.info(\n \"Tip: If you use GitHub CLI, you can use `GITHUB_TOKEN=$(gh auth token) rulesync fetch ...`\",\n );\n }\n}\n\n/**\n * Client for interacting with GitHub API using Octokit SDK\n */\nexport class GitHubClient {\n private readonly octokit: Octokit;\n private readonly hasToken: boolean;\n\n constructor(config: GitHubClientConfig = {}) {\n // Validate custom baseUrl uses HTTPS to prevent token exposure\n if (config.baseUrl && !config.baseUrl.startsWith(\"https://\")) {\n throw new GitHubClientError(\"GitHub API base URL must use HTTPS\");\n }\n\n this.hasToken = !!config.token;\n this.octokit = new Octokit({\n auth: config.token,\n baseUrl: config.baseUrl,\n });\n }\n\n /**\n * Get authentication token from various sources\n */\n static resolveToken(explicitToken?: string): string | undefined {\n if (explicitToken) {\n return explicitToken;\n }\n return process.env[\"GITHUB_TOKEN\"] ?? process.env[\"GH_TOKEN\"];\n }\n\n /**\n * Get the default branch of a repository\n */\n async getDefaultBranch(owner: string, repo: string): Promise<string> {\n const repoInfo = await this.getRepoInfo(owner, repo);\n return repoInfo.default_branch;\n }\n\n /**\n * Get repository information\n */\n async getRepoInfo(owner: string, repo: string): Promise<GitHubRepoInfo> {\n try {\n const { data } = await this.octokit.repos.get({ owner, repo });\n const parsed = GitHubRepoInfoSchema.safeParse(data);\n if (!parsed.success) {\n throw new GitHubClientError(\n `Invalid repository info response: ${formatError(parsed.error)}`,\n );\n }\n return parsed.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * List contents of a directory in a repository\n */\n async listDirectory(\n owner: string,\n repo: string,\n path: string,\n ref?: string,\n ): Promise<GitHubFileEntry[]> {\n try {\n const { data } = await this.octokit.repos.getContent({\n owner,\n repo,\n path,\n ref,\n });\n\n // API returns single object for files, array for directories\n if (!Array.isArray(data)) {\n throw new GitHubClientError(`Path \"${path}\" is not a directory`);\n }\n\n const entries: GitHubFileEntry[] = [];\n for (const item of data) {\n const parsed = GitHubFileEntrySchema.safeParse(item);\n if (parsed.success) {\n entries.push(parsed.data);\n }\n }\n return entries;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Get raw file content from a repository\n */\n async getFileContent(owner: string, repo: string, path: string, ref?: string): Promise<string> {\n try {\n const { data } = await this.octokit.repos.getContent({\n owner,\n repo,\n path,\n ref,\n mediaType: {\n format: \"raw\",\n },\n });\n\n // When using raw format, data is returned as a string\n if (typeof data === \"string\") {\n return data;\n }\n\n // Fallback: if data is an object with content (base64 encoded)\n if (!Array.isArray(data) && \"content\" in data && data.content) {\n return Buffer.from(data.content, \"base64\").toString(\"utf-8\");\n }\n\n throw new GitHubClientError(`Unexpected response format for file content`);\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Check if a file exists and is within size limits\n */\n async getFileInfo(\n owner: string,\n repo: string,\n path: string,\n ref?: string,\n ): Promise<GitHubFileEntry | null> {\n try {\n const { data } = await this.octokit.repos.getContent({\n owner,\n repo,\n path,\n ref,\n });\n\n // Ensure it's a file, not a directory\n if (Array.isArray(data)) {\n return null; // It's a directory\n }\n\n const parsed = GitHubFileEntrySchema.safeParse(data);\n if (!parsed.success) {\n return null;\n }\n\n if (parsed.data.size > MAX_FILE_SIZE) {\n throw new GitHubClientError(\n `File \"${path}\" exceeds maximum size limit of ${MAX_FILE_SIZE / 1024 / 1024}MB`,\n );\n }\n\n return parsed.data;\n } catch (error: unknown) {\n if (error instanceof RequestError && error.status === 404) {\n return null;\n }\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return null;\n }\n throw this.handleError(error);\n }\n }\n\n /**\n * Validate that a repository exists and is accessible\n */\n async validateRepository(owner: string, repo: string): Promise<boolean> {\n try {\n await this.getRepoInfo(owner, repo);\n return true;\n } catch (error) {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Resolve a ref (branch, tag, or SHA) to a full commit SHA.\n */\n async resolveRefToSha(owner: string, repo: string, ref: string): Promise<string> {\n try {\n const { data } = await this.octokit.repos.getCommit({\n owner,\n repo,\n ref,\n });\n return data.sha;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Get the latest release from a repository\n */\n async getLatestRelease(owner: string, repo: string): Promise<GitHubRelease> {\n try {\n const { data } = await this.octokit.repos.getLatestRelease({ owner, repo });\n const parsed = GitHubReleaseSchema.safeParse(data);\n if (!parsed.success) {\n throw new GitHubClientError(`Invalid release info response: ${formatError(parsed.error)}`);\n }\n return parsed.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Handle errors from Octokit and convert to GitHubClientError\n */\n private handleError(error: unknown): GitHubClientError {\n if (error instanceof GitHubClientError) {\n return error;\n }\n\n if (error instanceof RequestError) {\n const responseData = error.response?.data;\n const message = this.extractErrorMessage(responseData, error.message);\n const apiError: GitHubApiError | undefined = message ? { message } : undefined;\n const errorMessage = this.getErrorMessage(error.status, apiError);\n return new GitHubClientError(errorMessage, error.status, apiError);\n }\n\n if (error instanceof Error) {\n return new GitHubClientError(error.message);\n }\n\n return new GitHubClientError(\"Unknown error occurred\");\n }\n\n /**\n * Extract error message from response data\n */\n private extractErrorMessage(data: unknown, fallback: string): string {\n if (typeof data === \"object\" && data !== null && \"message\" in data) {\n const record = data as Record<string, unknown>;\n const msg = record[\"message\"];\n if (typeof msg === \"string\") {\n return msg;\n }\n }\n return fallback;\n }\n\n /**\n * Get human-readable error message for HTTP status codes\n */\n private getErrorMessage(statusCode: number, apiError?: GitHubApiError): string {\n const baseMessage = apiError?.message ?? `HTTP ${statusCode}`;\n\n switch (statusCode) {\n case 401:\n return `Authentication failed: ${baseMessage}. Check your GitHub token.`;\n case 403:\n if (baseMessage.toLowerCase().includes(\"rate limit\")) {\n return `GitHub API rate limit exceeded. ${this.hasToken ? \"Try again later.\" : \"Consider using a GitHub token.\"}`;\n }\n return `Access forbidden: ${baseMessage}. Check repository permissions.`;\n case 404:\n return `Not found: ${baseMessage}`;\n case 422:\n return `Invalid request: ${baseMessage}`;\n default:\n return `GitHub API error: ${baseMessage}`;\n }\n }\n}\n","import { Semaphore } from \"es-toolkit/promise\";\n\nimport type { GitHubFileEntry } from \"../types/fetch.js\";\nimport type { GitHubClient } from \"./github-client.js\";\n\nconst MAX_RECURSION_DEPTH = 15;\n\n/**\n * Execute an async function with semaphore-controlled concurrency.\n * Ensures the semaphore permit is always released, even if the function throws.\n */\nexport async function withSemaphore<T>(semaphore: Semaphore, fn: () => Promise<T>): Promise<T> {\n await semaphore.acquire();\n try {\n return await fn();\n } finally {\n semaphore.release();\n }\n}\n\n/**\n * Recursively list all files in a GitHub directory.\n */\nexport async function listDirectoryRecursive(params: {\n client: GitHubClient;\n owner: string;\n repo: string;\n path: string;\n ref?: string;\n depth?: number;\n semaphore: Semaphore;\n}): Promise<GitHubFileEntry[]> {\n const { client, owner, repo, path, ref, depth = 0, semaphore } = params;\n\n if (depth > MAX_RECURSION_DEPTH) {\n throw new Error(\n `Maximum recursion depth (${MAX_RECURSION_DEPTH}) exceeded while listing directory: ${path}`,\n );\n }\n\n // Semaphore is released here before recursive Promise.all below to avoid deadlock\n const entries = await withSemaphore(semaphore, () =>\n client.listDirectory(owner, repo, path, ref),\n );\n\n const files: GitHubFileEntry[] = [];\n const directories: GitHubFileEntry[] = [];\n\n for (const entry of entries) {\n if (entry.type === \"file\") {\n files.push(entry);\n } else if (entry.type === \"dir\") {\n directories.push(entry);\n }\n }\n\n const subResults = await Promise.all(\n directories.map((dir) =>\n listDirectoryRecursive({\n client,\n owner,\n repo,\n path: dir.path,\n ref,\n depth: depth + 1,\n semaphore,\n }),\n ),\n );\n\n return [...files, ...subResults.flat()];\n}\n","import { z } from \"zod/mini\";\n\n/**\n * Supported Git providers for fetch command\n */\nexport const ALL_GIT_PROVIDERS = [\"github\", \"gitlab\"] as const;\n\nconst GitProviderSchema = z.enum(ALL_GIT_PROVIDERS);\n\nexport type GitProvider = z.infer<typeof GitProviderSchema>;\n","import type { ParsedSource } from \"../types/fetch.js\";\nimport type { GitProvider } from \"../types/git-provider.js\";\nimport { ALL_GIT_PROVIDERS } from \"../types/git-provider.js\";\n\nconst GITHUB_HOSTS = new Set([\"github.com\", \"www.github.com\"]);\nconst GITLAB_HOSTS = new Set([\"gitlab.com\", \"www.gitlab.com\"]);\n\n/**\n * Parse source specification into components\n * Supports:\n * - URL format: https://github.com/owner/repo, https://gitlab.com/owner/repo\n * - Prefix format: github:owner/repo, gitlab:owner/repo\n * - Shorthand format: owner/repo (defaults to GitHub)\n * - With ref: owner/repo@ref\n * - With path: owner/repo:path\n * - Combined: owner/repo@ref:path\n */\nexport function parseSource(source: string): ParsedSource {\n // Handle full URL format (https://...)\n if (source.startsWith(\"http://\") || source.startsWith(\"https://\")) {\n return parseUrl(source);\n }\n\n // Handle prefix format (github:owner/repo, gitlab:owner/repo)\n if (source.includes(\":\") && !source.includes(\"://\")) {\n const colonIndex = source.indexOf(\":\");\n const prefix = source.substring(0, colonIndex);\n const rest = source.substring(colonIndex + 1);\n\n // Check if prefix is a known provider using type guard\n const provider = ALL_GIT_PROVIDERS.find((p) => p === prefix);\n if (provider) {\n return { provider, ...parseShorthand(rest) };\n }\n\n // If prefix is not a known provider, treat the whole thing as shorthand\n // This handles cases like owner/repo:path where \"owner/repo\" contains no provider prefix\n return { provider: \"github\", ...parseShorthand(source) };\n }\n\n // Handle shorthand: owner/repo[@ref][:path] - defaults to GitHub\n return { provider: \"github\", ...parseShorthand(source) };\n}\n\n/**\n * Parse URL format into components\n */\nfunction parseUrl(url: string): ParsedSource {\n const urlObj = new URL(url);\n const host = urlObj.hostname.toLowerCase();\n\n let provider: GitProvider;\n if (GITHUB_HOSTS.has(host)) {\n provider = \"github\";\n } else if (GITLAB_HOSTS.has(host)) {\n provider = \"gitlab\";\n } else {\n throw new Error(\n `Unknown Git provider for host: ${host}. Supported providers: ${ALL_GIT_PROVIDERS.join(\", \")}`,\n );\n }\n\n // Split by path segments\n const segments = urlObj.pathname.split(\"/\").filter(Boolean);\n\n if (segments.length < 2) {\n throw new Error(`Invalid ${provider} URL: ${url}. Expected format: https://${host}/owner/repo`);\n }\n\n const owner = segments[0];\n const repo = segments[1]?.replace(/\\.git$/, \"\");\n\n // Check for /tree/ref/path or /blob/ref/path pattern\n if (segments.length > 2 && (segments[2] === \"tree\" || segments[2] === \"blob\")) {\n const ref = segments[3];\n const path = segments.length > 4 ? segments.slice(4).join(\"/\") : undefined;\n return {\n provider,\n owner: owner ?? \"\",\n repo: repo ?? \"\",\n ref,\n path,\n };\n }\n\n return {\n provider,\n owner: owner ?? \"\",\n repo: repo ?? \"\",\n };\n}\n\n/**\n * Parse shorthand format (without provider prefix)\n */\nfunction parseShorthand(source: string): Omit<ParsedSource, \"provider\"> {\n // Pattern: owner/repo[@ref][:path]\n let remaining = source;\n let path: string | undefined;\n let ref: string | undefined;\n\n // Extract path first (after :)\n const colonIndex = remaining.indexOf(\":\");\n if (colonIndex !== -1) {\n path = remaining.substring(colonIndex + 1);\n if (!path) {\n throw new Error(`Invalid source: ${source}. Path cannot be empty after \":\".`);\n }\n remaining = remaining.substring(0, colonIndex);\n }\n\n // Extract ref (after @)\n const atIndex = remaining.indexOf(\"@\");\n if (atIndex !== -1) {\n ref = remaining.substring(atIndex + 1);\n if (!ref) {\n throw new Error(`Invalid source: ${source}. Ref cannot be empty after \"@\".`);\n }\n remaining = remaining.substring(0, atIndex);\n }\n\n // Parse owner/repo\n const slashIndex = remaining.indexOf(\"/\");\n if (slashIndex === -1) {\n throw new Error(\n `Invalid source: ${source}. Expected format: owner/repo, owner/repo@ref, or owner/repo:path`,\n );\n }\n\n const owner = remaining.substring(0, slashIndex);\n const repo = remaining.substring(slashIndex + 1);\n\n if (!owner || !repo) {\n throw new Error(`Invalid source: ${source}. Both owner and repo are required.`);\n }\n\n return {\n owner,\n repo,\n ref,\n path,\n };\n}\n","import { join, posix } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport {\n FETCH_CONCURRENCY_LIMIT,\n MAX_FILE_SIZE,\n RULESYNC_AIIGNORE_FILE_NAME,\n RULESYNC_HOOKS_FILE_NAME,\n RULESYNC_HOOKS_JSONC_FILE_NAME,\n RULESYNC_MCP_FILE_NAME,\n RULESYNC_MCP_JSONC_FILE_NAME,\n RULESYNC_PERMISSIONS_FILE_NAME,\n RULESYNC_PERMISSIONS_JSONC_FILE_NAME,\n RULESYNC_RELATIVE_DIR_PATH,\n} from \"../constants/rulesync-paths.js\";\nimport { ChecksProcessor } from \"../features/checks/checks-processor.js\";\nimport { CommandsProcessor } from \"../features/commands/commands-processor.js\";\nimport { HooksProcessor } from \"../features/hooks/hooks-processor.js\";\nimport { IgnoreProcessor } from \"../features/ignore/ignore-processor.js\";\nimport { McpProcessor } from \"../features/mcp/mcp-processor.js\";\nimport { RulesProcessor } from \"../features/rules/rules-processor.js\";\nimport { SkillsProcessor } from \"../features/skills/skills-processor.js\";\nimport { SubagentsProcessor } from \"../features/subagents/subagents-processor.js\";\nimport type { Feature } from \"../types/features.js\";\nimport { ALL_FEATURES } from \"../types/features.js\";\nimport type { FetchTarget } from \"../types/fetch-targets.js\";\nimport type {\n ConflictStrategy,\n FetchFileResult,\n FetchOptions,\n FetchSummary,\n GitHubFileEntry,\n ParsedSource,\n} from \"../types/fetch.js\";\nimport type { ToolTarget } from \"../types/tool-targets.js\";\nimport {\n checkPathTraversal,\n createTempDirectory,\n fileExists,\n removeTempDirectory,\n toPosixPath,\n writeFileContent,\n} from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { GitHubClient, GitHubClientError } from \"./github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"./github-utils.js\";\nimport { parseSource } from \"./source-parser.js\";\n\n/**\n * Feature to path mapping for filtering (rulesync format)\n */\nconst FEATURE_PATHS: Record<Feature, string[]> = {\n rules: [\"rules\"],\n commands: [\"commands\"],\n subagents: [\"subagents\"],\n skills: [\"skills\"],\n checks: [\"checks\"],\n ignore: [RULESYNC_AIIGNORE_FILE_NAME],\n mcp: [RULESYNC_MCP_FILE_NAME, RULESYNC_MCP_JSONC_FILE_NAME],\n hooks: [RULESYNC_HOOKS_FILE_NAME, RULESYNC_HOOKS_JSONC_FILE_NAME],\n permissions: [RULESYNC_PERMISSIONS_FILE_NAME, RULESYNC_PERMISSIONS_JSONC_FILE_NAME],\n};\n\n/**\n * Check if target is a tool target (not rulesync)\n */\nfunction isToolTarget(target: FetchTarget): target is ToolTarget {\n return target !== \"rulesync\";\n}\n\n/**\n * Validate file size against maximum limit\n * @throws {GitHubClientError} If file size exceeds limit\n */\nfunction validateFileSize(relativePath: string, size: number): void {\n if (size > MAX_FILE_SIZE) {\n throw new GitHubClientError(\n `File \"${relativePath}\" exceeds maximum size limit (${(size / 1024 / 1024).toFixed(2)}MB > ${MAX_FILE_SIZE / 1024 / 1024}MB)`,\n );\n }\n}\n\n/**\n * Result of feature conversion\n */\ntype FeatureConversionResult = {\n converted: number;\n convertedPaths: string[];\n};\n\n/**\n * Processor type for feature conversion\n */\ntype FeatureProcessor = {\n loadToolFiles(): Promise<unknown[]>;\n convertToolFilesToRulesyncFiles(\n toolFiles: unknown[],\n ): Promise<\n Array<{ getRelativeDirPath(): string; getRelativeFilePath(): string; getFileContent(): string }>\n >;\n};\n\n/**\n * Process feature conversion for a single feature type\n * @param processor - The processor to use for loading and converting files\n * @param outputDir - Output directory for converted files\n * @returns The paths of converted files\n */\nasync function processFeatureConversion(params: {\n processor: FeatureProcessor;\n outputDir: string;\n}): Promise<{ paths: string[] }> {\n const { processor, outputDir } = params;\n const paths: string[] = [];\n\n const toolFiles = await processor.loadToolFiles();\n if (toolFiles.length === 0) {\n return { paths: [] };\n }\n\n const rulesyncFiles = await processor.convertToolFilesToRulesyncFiles(toolFiles);\n for (const file of rulesyncFiles) {\n const relativePath = join(file.getRelativeDirPath(), file.getRelativeFilePath());\n const outputPath = join(outputDir, relativePath);\n await writeFileContent(outputPath, file.getFileContent());\n paths.push(relativePath);\n }\n\n return { paths };\n}\n\n/**\n * Convert fetched tool-specific files to rulesync format\n * @param tempDir - Temporary directory containing tool-specific files\n * @param outputDir - Output directory for rulesync files\n * @param target - Tool target to convert from\n * @param features - Features to convert\n * @returns Number of converted files and their paths\n */\nasync function convertFetchedFilesToRulesync(params: {\n tempDir: string;\n outputDir: string;\n target: ToolTarget;\n features: Feature[];\n logger: Logger;\n}): Promise<FeatureConversionResult> {\n const { tempDir, outputDir, target, features, logger } = params;\n const convertedPaths: string[] = [];\n\n // Feature conversion configurations\n // Each config defines how to get supported targets and create a processor\n const featureConfigs: Array<{\n feature: Feature;\n getTargets: () => ToolTarget[];\n createProcessor: () => FeatureProcessor;\n }> = [\n {\n feature: \"rules\",\n getTargets: () => RulesProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new RulesProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"commands\",\n getTargets: () =>\n CommandsProcessor.getToolTargets({ global: false, includeSimulated: false }),\n createProcessor: () =>\n new CommandsProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"subagents\",\n getTargets: () =>\n SubagentsProcessor.getToolTargets({ global: false, includeSimulated: false }),\n createProcessor: () =>\n new SubagentsProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"checks\",\n getTargets: () => ChecksProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new ChecksProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"ignore\",\n getTargets: () => IgnoreProcessor.getToolTargets(),\n createProcessor: () =>\n new IgnoreProcessor({ outputRoot: tempDir, toolTarget: target, logger }),\n },\n {\n feature: \"mcp\",\n getTargets: () => McpProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new McpProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n {\n feature: \"hooks\",\n getTargets: () => HooksProcessor.getToolTargets({ global: false }),\n createProcessor: () =>\n new HooksProcessor({ outputRoot: tempDir, toolTarget: target, global: false, logger }),\n },\n ];\n\n // Process each feature using data-driven approach\n for (const config of featureConfigs) {\n if (!features.includes(config.feature)) {\n continue;\n }\n const supportedTargets = config.getTargets();\n if (!supportedTargets.includes(target)) {\n continue;\n }\n const processor = config.createProcessor();\n const result = await processFeatureConversion({ processor, outputDir });\n convertedPaths.push(...result.paths);\n }\n\n // Skills conversion is not yet supported in fetch command\n // Note: Skills are more complex as they are directory-based.\n // Users can use the import command for skills conversion.\n if (features.includes(\"skills\")) {\n logger.debug(\n \"Skills conversion is not yet supported in fetch command. Use import command instead.\",\n );\n }\n\n return { converted: convertedPaths.length, convertedPaths };\n}\n\n/**\n * Resolve features from options, handling wildcard\n */\nfunction resolveFeatures(features?: string[]): Feature[] {\n if (!features || features.length === 0 || features.includes(\"*\")) {\n return [...ALL_FEATURES];\n }\n return features.filter((f): f is Feature => ALL_FEATURES.includes(f as Feature));\n}\n\n/**\n * Type guard for error objects with statusCode\n */\nfunction hasStatusCode(error: unknown): error is { statusCode: number } {\n if (typeof error !== \"object\" || error === null || !(\"statusCode\" in error)) {\n return false;\n }\n const maybeStatus = Object.getOwnPropertyDescriptor(error, \"statusCode\")?.value;\n return typeof maybeStatus === \"number\";\n}\n\n/**\n * Check if error is a 404 \"not found\" error\n */\nfunction isNotFoundError(error: unknown): boolean {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return true;\n }\n // Also handle plain objects with statusCode property (for test mocks)\n if (hasStatusCode(error) && error.statusCode === 404) {\n return true;\n }\n return false;\n}\n\n/**\n * Parameters for fetch operation\n */\nexport type FetchParams = {\n source: string;\n options?: FetchOptions;\n outputRoot?: string;\n logger: Logger;\n};\n\n/**\n * Fetch files from a Git repository\n * Searches for feature directories (rules/, commands/, skills/, etc.) directly at the specified path\n *\n * When target is \"rulesync\" (default), files are fetched as-is.\n * When target is a tool target (e.g., \"claudecode\"), files are fetched to a temp directory,\n * converted to rulesync format, and written to the output directory.\n */\nexport async function fetchFiles(params: FetchParams): Promise<FetchSummary> {\n const { source, options = {}, outputRoot = process.cwd(), logger } = params;\n\n // Parse source\n const parsed = parseSource(source);\n\n // Check if provider is supported\n if (parsed.provider === \"gitlab\") {\n throw new Error(\n \"GitLab is not yet supported. Currently only GitHub repositories are supported.\",\n );\n }\n\n // Resolve options\n const resolvedRef = options.ref ?? parsed.ref;\n // Normalize backslashes to forward slashes for GitHub API compatibility.\n const resolvedPath = toPosixPath(options.path ?? parsed.path ?? \".\");\n const outputDir = options.output ?? RULESYNC_RELATIVE_DIR_PATH;\n const conflictStrategy: ConflictStrategy = options.conflict ?? \"overwrite\";\n const enabledFeatures = resolveFeatures(options.features);\n const target: FetchTarget = options.target ?? \"rulesync\";\n\n // Validate output directory to prevent path traversal attacks\n checkPathTraversal({\n relativePath: outputDir,\n intendedRootDir: outputRoot,\n });\n\n // Initialize GitHub client\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n\n // Validate repository\n logger.debug(`Validating repository: ${parsed.owner}/${parsed.repo}`);\n const isValid = await client.validateRepository(parsed.owner, parsed.repo);\n if (!isValid) {\n throw new GitHubClientError(\n `Repository not found: ${parsed.owner}/${parsed.repo}. Check the repository name and your access permissions.`,\n 404,\n );\n }\n\n // Resolve ref to use\n const ref = resolvedRef ?? (await client.getDefaultBranch(parsed.owner, parsed.repo));\n logger.debug(`Using ref: ${ref}`);\n\n // If target is a tool format, use conversion flow\n if (isToolTarget(target)) {\n return fetchAndConvertToolFiles({\n client,\n parsed,\n ref,\n resolvedPath,\n enabledFeatures,\n target,\n outputDir,\n outputRoot,\n conflictStrategy,\n logger,\n });\n }\n\n // Create semaphore for concurrency control\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n // Collect all files to fetch from feature directories directly\n const filesToFetch = await collectFeatureFiles({\n client,\n owner: parsed.owner,\n repo: parsed.repo,\n basePath: resolvedPath,\n ref,\n enabledFeatures,\n semaphore,\n logger,\n });\n\n if (filesToFetch.length === 0) {\n logger.warn(`No files found matching enabled features: ${enabledFeatures.join(\", \")}`);\n return {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: [],\n created: 0,\n overwritten: 0,\n skipped: 0,\n };\n }\n\n // Process files in parallel with concurrency control\n const outputBasePath = join(outputRoot, outputDir);\n\n // Validate paths and check file sizes first (synchronous checks)\n for (const { relativePath, size } of filesToFetch) {\n checkPathTraversal({\n relativePath,\n intendedRootDir: outputBasePath,\n });\n\n validateFileSize(relativePath, size);\n }\n\n // Process files in parallel with concurrency control\n // Note: Promise.all fails fast - if any promise rejects, others continue running but\n // may have already written files. This behavior is consistent with sequential execution,\n // but the window for partial writes is larger with parallel execution.\n const results = await Promise.all(\n filesToFetch.map(async ({ remotePath, relativePath }) => {\n const localPath = join(outputBasePath, relativePath);\n const exists = await fileExists(localPath);\n\n if (exists && conflictStrategy === \"skip\") {\n logger.debug(`Skipping existing file: ${relativePath}`);\n return { relativePath, status: \"skipped\" as const };\n }\n\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, remotePath, ref),\n );\n await writeFileContent(localPath, content);\n\n const status = exists ? (\"overwritten\" as const) : (\"created\" as const);\n logger.debug(`Wrote: ${relativePath} (${status})`);\n return { relativePath, status };\n }),\n );\n\n // Calculate summary\n const summary: FetchSummary = {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: results,\n created: results.filter((r) => r.status === \"created\").length,\n overwritten: results.filter((r) => r.status === \"overwritten\").length,\n skipped: results.filter((r) => r.status === \"skipped\").length,\n };\n\n return summary;\n}\n\n/**\n * Collect files from feature directories\n */\nasync function collectFeatureFiles(params: {\n client: GitHubClient;\n owner: string;\n repo: string;\n basePath: string;\n ref: string;\n enabledFeatures: Feature[];\n semaphore: Semaphore;\n logger: Logger;\n}): Promise<Array<{ remotePath: string; relativePath: string; size: number }>> {\n const { client, owner, repo, basePath, ref, enabledFeatures, semaphore, logger } = params;\n\n // Cache directory listing results to avoid duplicate API calls\n // File-based features (ignore, mcp, hooks) all list the same basePath directory\n const dirCache = new Map<string, Promise<GitHubFileEntry[]>>();\n\n async function getCachedDirectory(path: string): Promise<GitHubFileEntry[]> {\n let promise = dirCache.get(path);\n if (promise === undefined) {\n promise = withSemaphore(semaphore, () => client.listDirectory(owner, repo, path, ref));\n dirCache.set(path, promise);\n }\n return promise;\n }\n\n const tasks = enabledFeatures.flatMap((feature) =>\n FEATURE_PATHS[feature].map((featurePath) => ({ feature, featurePath })),\n );\n\n const results = await Promise.all(\n tasks.map(async ({ featurePath }) => {\n const fullPath =\n basePath === \".\" || basePath === \"\" ? featurePath : posix.join(basePath, featurePath);\n const collected: Array<{ remotePath: string; relativePath: string; size: number }> = [];\n\n try {\n // Check if it's a file (mcp.json, .aiignore, hooks.json)\n if (featurePath.includes(\".\")) {\n // Try to get the file directly\n try {\n const entries = await getCachedDirectory(\n basePath === \".\" || basePath === \"\" ? \".\" : basePath,\n );\n const fileEntry = entries.find((e) => e.name === featurePath && e.type === \"file\");\n if (fileEntry) {\n collected.push({\n remotePath: fileEntry.path,\n relativePath: featurePath,\n size: fileEntry.size,\n });\n }\n } catch (error) {\n // Only skip 404 errors (file not found), re-throw other errors\n if (isNotFoundError(error)) {\n logger.debug(`File not found: ${fullPath}`);\n } else {\n throw error;\n }\n }\n } else {\n // It's a directory (rules/, commands/, skills/, subagents/)\n const dirFiles = await listDirectoryRecursive({\n client,\n owner,\n repo,\n path: fullPath,\n ref,\n semaphore,\n });\n\n for (const file of dirFiles) {\n // Calculate relative path from base\n const relativePath =\n basePath === \".\" || basePath === \"\"\n ? file.path\n : file.path.substring(basePath.length + 1);\n\n collected.push({\n remotePath: file.path,\n relativePath,\n size: file.size,\n });\n }\n }\n } catch (error) {\n // Check for 404 errors (feature not found)\n if (isNotFoundError(error)) {\n // Feature directory/file not found, skip silently\n logger.debug(`Feature not found: ${fullPath}`);\n return collected;\n }\n throw error;\n }\n\n return collected;\n }),\n );\n\n return results.flat();\n}\n\n/**\n * Fetch tool-specific files and convert them to rulesync format\n */\nasync function fetchAndConvertToolFiles(params: {\n client: GitHubClient;\n parsed: ParsedSource;\n ref: string;\n resolvedPath: string;\n enabledFeatures: Feature[];\n target: ToolTarget;\n outputDir: string;\n outputRoot: string;\n conflictStrategy: ConflictStrategy;\n logger: Logger;\n}): Promise<FetchSummary> {\n const {\n client,\n parsed,\n ref,\n resolvedPath,\n enabledFeatures,\n target,\n outputDir,\n outputRoot,\n conflictStrategy: _conflictStrategy,\n logger,\n } = params;\n\n // Create a unique temporary directory\n const tempDir = await createTempDirectory();\n logger.debug(`Created temp directory: ${tempDir}`);\n\n // Create semaphore for concurrency control\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n try {\n // Collect files using rulesync feature paths (rules/, commands/, etc.)\n // External repos use these paths directly without tool-specific prefixes\n const filesToFetch = await collectFeatureFiles({\n client,\n owner: parsed.owner,\n repo: parsed.repo,\n basePath: resolvedPath,\n ref,\n enabledFeatures,\n semaphore,\n logger,\n });\n\n if (filesToFetch.length === 0) {\n logger.warn(`No files found matching enabled features: ${enabledFeatures.join(\", \")}`);\n return {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: [],\n created: 0,\n overwritten: 0,\n skipped: 0,\n };\n }\n\n // Validate file sizes first\n for (const { relativePath, size } of filesToFetch) {\n validateFileSize(relativePath, size);\n }\n\n // Fetch files to temp directory with tool-specific structure in parallel\n // Map rulesync paths to tool-specific paths\n const toolPaths = getToolPathMapping(target);\n\n await Promise.all(\n filesToFetch.map(async ({ remotePath, relativePath }) => {\n // Map the relative path to tool-specific structure\n const toolRelativePath = mapToToolPath(relativePath, toolPaths);\n checkPathTraversal({\n relativePath: toolRelativePath,\n intendedRootDir: tempDir,\n });\n const localPath = join(tempDir, toolRelativePath);\n\n // Fetch file content with concurrency control, then write locally\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, remotePath, ref),\n );\n await writeFileContent(localPath, content);\n logger.debug(`Fetched to temp: ${toolRelativePath}`);\n }),\n );\n\n // Convert fetched files to rulesync format\n const outputBasePath = join(outputRoot, outputDir);\n const { converted, convertedPaths } = await convertFetchedFilesToRulesync({\n tempDir,\n outputDir: outputBasePath,\n target,\n features: enabledFeatures,\n logger,\n });\n\n // Build results based on conversion with actual file paths\n const results: FetchFileResult[] = convertedPaths.map((relativePath) => ({\n relativePath,\n status: \"created\" as const,\n }));\n\n logger.debug(`Converted ${converted} files from ${target} format to rulesync format`);\n\n return {\n source: `${parsed.owner}/${parsed.repo}`,\n ref,\n files: results,\n created: results.filter((r) => r.status === \"created\").length,\n overwritten: results.filter((r) => r.status === \"overwritten\").length,\n skipped: results.filter((r) => r.status === \"skipped\").length,\n };\n } finally {\n // Clean up temp directory\n await removeTempDirectory(tempDir);\n }\n}\n\n/**\n * Get tool-specific path mapping for a target\n * Returns a mapping from rulesync feature paths to tool-specific paths\n */\nfunction getToolPathMapping(target: ToolTarget): {\n rules?: { root?: string; nonRoot?: string };\n commands?: string;\n subagents?: string;\n skills?: string;\n checks?: string;\n} {\n // Get tool-specific paths from each processor class\n const mapping: {\n rules?: { root?: string; nonRoot?: string };\n commands?: string;\n subagents?: string;\n skills?: string;\n checks?: string;\n } = {};\n\n // Rules paths\n const supportedRulesTargets = RulesProcessor.getToolTargets({ global: false });\n if (supportedRulesTargets.includes(target)) {\n const factory = RulesProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.rules = {\n root: paths.root?.relativeFilePath,\n nonRoot: paths.nonRoot?.relativeDirPath,\n };\n }\n }\n\n // Commands paths\n const supportedCommandsTargets = CommandsProcessor.getToolTargets({\n global: false,\n includeSimulated: false,\n });\n if (supportedCommandsTargets.includes(target)) {\n const factory = CommandsProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.commands = paths.relativeDirPath;\n }\n }\n\n // Subagents paths\n const supportedSubagentsTargets = SubagentsProcessor.getToolTargets({\n global: false,\n includeSimulated: false,\n });\n if (supportedSubagentsTargets.includes(target)) {\n const factory = SubagentsProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.subagents = paths.relativeDirPath;\n }\n }\n\n // Skills paths\n const supportedSkillsTargets = SkillsProcessor.getToolTargets({ global: false });\n if (supportedSkillsTargets.includes(target)) {\n const factory = SkillsProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.skills = paths.relativeDirPath;\n }\n }\n\n // Checks paths\n const supportedChecksTargets = ChecksProcessor.getToolTargets({ global: false });\n if (supportedChecksTargets.includes(target)) {\n const factory = ChecksProcessor.getFactory(target);\n if (factory) {\n const paths = factory.class.getSettablePaths({ global: false });\n mapping.checks = paths.relativeDirPath;\n }\n }\n\n return mapping;\n}\n\n/**\n * Map a rulesync-style relative path to tool-specific path\n */\nfunction mapToToolPath(\n relativePath: string,\n toolPaths: ReturnType<typeof getToolPathMapping>,\n): string {\n // Check if this is a rules file\n if (relativePath.startsWith(\"rules/\")) {\n const restPath = relativePath.substring(\"rules/\".length);\n if (toolPaths.rules?.nonRoot) {\n return join(toolPaths.rules.nonRoot, restPath);\n }\n }\n\n // Check if this is a root rule file (e.g., CLAUDE.md, AGENTS.md)\n if (toolPaths.rules?.root && relativePath === toolPaths.rules.root) {\n return relativePath;\n }\n\n // Check if this is a commands file\n if (relativePath.startsWith(\"commands/\")) {\n const restPath = relativePath.substring(\"commands/\".length);\n if (toolPaths.commands) {\n return join(toolPaths.commands, restPath);\n }\n }\n\n // Check if this is a subagents file\n if (relativePath.startsWith(\"subagents/\")) {\n const restPath = relativePath.substring(\"subagents/\".length);\n if (toolPaths.subagents) {\n return join(toolPaths.subagents, restPath);\n }\n }\n\n // Check if this is a skills file\n if (relativePath.startsWith(\"skills/\")) {\n const restPath = relativePath.substring(\"skills/\".length);\n if (toolPaths.skills) {\n return join(toolPaths.skills, restPath);\n }\n }\n\n // Check if this is a checks file\n if (relativePath.startsWith(\"checks/\")) {\n const restPath = relativePath.substring(\"checks/\".length);\n if (toolPaths.checks) {\n return join(toolPaths.checks, restPath);\n }\n }\n\n // Default: return as-is\n return relativePath;\n}\n\n/**\n * Format fetch summary for display\n */\nexport function formatFetchSummary(summary: FetchSummary): string {\n const lines: string[] = [];\n\n lines.push(`Fetched from ${summary.source}@${summary.ref}:`);\n\n for (const file of summary.files) {\n const icon = file.status === \"skipped\" ? \"-\" : \"\\u2713\";\n const statusText =\n file.status === \"created\"\n ? \"(created)\"\n : file.status === \"overwritten\"\n ? \"(overwritten)\"\n : \"(skipped - already exists)\";\n lines.push(` ${icon} ${file.relativePath} ${statusText}`);\n }\n\n const parts: string[] = [];\n if (summary.created > 0) parts.push(`${summary.created} created`);\n if (summary.overwritten > 0) parts.push(`${summary.overwritten} overwritten`);\n if (summary.skipped > 0) parts.push(`${summary.skipped} skipped`);\n\n lines.push(\"\");\n const summaryText = parts.length > 0 ? parts.join(\", \") : \"no files\";\n lines.push(`Summary: ${summaryText}`);\n\n return lines.join(\"\\n\");\n}\n","import { fetchFiles, formatFetchSummary } from \"../../lib/fetch.js\";\nimport { GitHubClientError } from \"../../lib/github-client.js\";\nimport type { FetchOptions } from \"../../types/fetch.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\nexport type FetchCommandOptions = FetchOptions & {\n source: string;\n};\n\nexport async function fetchCommand(logger: Logger, options: FetchCommandOptions): Promise<void> {\n const { source, ...fetchOptions } = options;\n\n logger.debug(`Fetching files from ${source}...`);\n\n try {\n const summary = await fetchFiles({\n source,\n options: fetchOptions,\n logger,\n });\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n const createdFiles = summary.files\n .filter((f) => f.status === \"created\")\n .map((f) => f.relativePath);\n const overwrittenFiles = summary.files\n .filter((f) => f.status === \"overwritten\")\n .map((f) => f.relativePath);\n const skippedFiles = summary.files\n .filter((f) => f.status === \"skipped\")\n .map((f) => f.relativePath);\n\n logger.captureData(\"source\", source);\n logger.captureData(\"path\", fetchOptions.path);\n logger.captureData(\"created\", createdFiles);\n logger.captureData(\"overwritten\", overwrittenFiles);\n logger.captureData(\"skipped\", skippedFiles);\n logger.captureData(\"totalFetched\", summary.created + summary.overwritten + summary.skipped);\n }\n\n const output = formatFetchSummary(summary);\n\n logger.success(output);\n\n // Exit with appropriate code\n if (summary.created + summary.overwritten === 0 && summary.skipped === 0) {\n logger.warn(\"No files were fetched.\");\n }\n } catch (error) {\n if (error instanceof GitHubClientError) {\n // Include auth hints in error message for JSON mode\n const authHint =\n error.statusCode === 401 || error.statusCode === 403\n ? \" Tip: Set GITHUB_TOKEN or GH_TOKEN environment variable, or use `GITHUB_TOKEN=$(gh auth token) rulesync fetch ...`\"\n : \"\";\n throw new CLIError(`GitHub API Error: ${error.message}.${authHint}`, ErrorCodes.FETCH_FAILED);\n }\n throw error;\n }\n}\n","import { ConfigResolver, type ConfigResolverResolveParams } from \"../../config/config-resolver.js\";\nimport { checkRulesyncDirExists, generate, type GenerateResult } from \"../../lib/generate.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { calculateTotalCount } from \"../../utils/result.js\";\n\nexport type GenerateOptions = ConfigResolverResolveParams;\n\n/**\n * Log feature generation result with appropriate prefix based on dry run mode.\n */\nfunction logFeatureResult(\n logger: Logger,\n params: {\n count: number;\n paths: string[];\n featureName: string;\n isPreview: boolean;\n modePrefix: string;\n },\n): void {\n const { count, paths, featureName, isPreview, modePrefix } = params;\n if (count > 0) {\n if (isPreview) {\n logger.info(`${modePrefix} Would write ${count} ${featureName}`);\n } else {\n logger.success(`Written ${count} ${featureName}`);\n }\n for (const p of paths) {\n logger.info(` ${p}`);\n }\n }\n}\n\nconst FEATURE_DEBUG_MESSAGES: Record<string, string> = {\n ignore: \"Generating ignore files...\",\n mcp: \"Generating MCP files...\",\n commands: \"Generating command files...\",\n subagents: \"Generating subagent files...\",\n skills: \"Generating skill files...\",\n hooks: \"Generating hooks...\",\n checks: \"Generating check files...\",\n rules: \"Generating rule files...\",\n};\n\n// Order in which per-feature debug messages are emitted; matches the original\n// sequential `if (features.includes(...))` ladder.\nconst FEATURE_DEBUG_ORDER = [\n \"ignore\",\n \"mcp\",\n \"commands\",\n \"subagents\",\n \"skills\",\n \"hooks\",\n \"checks\",\n \"rules\",\n] as const;\n\nfunction logFeatureDebugMessages(logger: Logger, features: readonly string[]): void {\n for (const feature of FEATURE_DEBUG_ORDER) {\n if (features.includes(feature)) {\n logger.debug(FEATURE_DEBUG_MESSAGES[feature] ?? \"\");\n }\n }\n}\n\n/**\n * Build the human-readable per-feature summary fragments (e.g. \"3 rules\") for\n * features that produced at least one file. Order matches the original\n * sequential `if (count > 0) parts.push(...)` ladder.\n */\nfunction buildSummaryParts(result: GenerateResult): string[] {\n const summarySpecs: { count: number; label: string }[] = [\n { count: result.rulesCount, label: \"rules\" },\n { count: result.ignoreCount, label: \"ignore files\" },\n { count: result.mcpCount, label: \"MCP files\" },\n { count: result.commandsCount, label: \"commands\" },\n { count: result.subagentsCount, label: \"subagents\" },\n { count: result.skillsCount, label: \"skills\" },\n { count: result.hooksCount, label: \"hooks\" },\n { count: result.permissionsCount, label: \"permissions\" },\n { count: result.checksCount, label: \"checks\" },\n ];\n\n const parts: string[] = [];\n for (const { count, label } of summarySpecs) {\n if (count > 0) parts.push(`${count} ${label}`);\n }\n return parts;\n}\n\nexport async function generateCommand(logger: Logger, options: GenerateOptions): Promise<void> {\n const config = await ConfigResolver.resolve(options, { logger });\n\n const check = config.getCheck();\n\n const isPreview = config.isPreviewMode();\n const modePrefix = isPreview ? \"[DRY RUN]\" : \"\";\n\n logger.debug(\"Generating files...\");\n\n if (!(await checkRulesyncDirExists({ inputRoot: config.getInputRoot() }))) {\n throw new CLIError(\n \".rulesync directory not found. Run 'rulesync init' first.\",\n ErrorCodes.RULESYNC_DIR_NOT_FOUND,\n );\n }\n\n logger.debug(`Output roots: ${config.getOutputRoots().join(\", \")}`);\n\n const features = config.getFeatures();\n\n logFeatureDebugMessages(logger, features);\n\n const result = await generate({ config, logger });\n\n const totalGenerated = calculateTotalCount(result);\n\n // Log feature results and capture data for JSON mode\n const featureResults = {\n ignore: { count: result.ignoreCount, paths: result.ignorePaths },\n mcp: { count: result.mcpCount, paths: result.mcpPaths },\n commands: { count: result.commandsCount, paths: result.commandsPaths },\n subagents: { count: result.subagentsCount, paths: result.subagentsPaths },\n skills: { count: result.skillsCount, paths: result.skillsPaths },\n hooks: { count: result.hooksCount, paths: result.hooksPaths },\n permissions: { count: result.permissionsCount, paths: result.permissionsPaths },\n checks: { count: result.checksCount, paths: result.checksPaths },\n rules: { count: result.rulesCount, paths: result.rulesPaths },\n };\n\n // Map feature keys to human-readable labels with pluralization\n const featureLabels: Record<string, (count: number) => string> = {\n rules: (count) => `${count === 1 ? \"rule\" : \"rules\"}`,\n ignore: (count) => `${count === 1 ? \"ignore file\" : \"ignore files\"}`,\n mcp: (count) => `${count === 1 ? \"MCP file\" : \"MCP files\"}`,\n commands: (count) => `${count === 1 ? \"command\" : \"commands\"}`,\n subagents: (count) => `${count === 1 ? \"subagent\" : \"subagents\"}`,\n skills: (count) => `${count === 1 ? \"skill\" : \"skills\"}`,\n hooks: (count) => `${count === 1 ? \"hooks file\" : \"hooks files\"}`,\n permissions: (count) => `${count === 1 ? \"permissions file\" : \"permissions files\"}`,\n checks: (count) => `${count === 1 ? \"check\" : \"checks\"}`,\n };\n\n for (const [feature, data] of Object.entries(featureResults)) {\n logFeatureResult(logger, {\n count: data.count,\n paths: data.paths,\n featureName: featureLabels[feature]?.(data.count) ?? feature,\n isPreview,\n modePrefix,\n });\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"features\", featureResults);\n logger.captureData(\"totalFiles\", totalGenerated);\n logger.captureData(\"hasDiff\", result.hasDiff);\n logger.captureData(\"skills\", result.skills ?? []);\n }\n\n // Check mode must fail even when the change is delete-only and no files are written.\n if (check) {\n if (result.hasDiff) {\n throw new CLIError(\n \"Files are not up to date. Run 'rulesync generate' to update.\",\n ErrorCodes.GENERATION_FAILED,\n );\n }\n\n logger.success(\"✓ All files are up to date.\");\n return;\n }\n\n if (totalGenerated === 0) {\n const enabledFeatures = features.join(\", \");\n logger.info(`✓ All files are up to date (${enabledFeatures})`);\n return;\n }\n\n const parts = buildSummaryParts(result);\n\n if (isPreview) {\n logger.info(`${modePrefix} Would write ${totalGenerated} file(s) total (${parts.join(\" + \")})`);\n } else {\n logger.success(`🎉 All done! Written ${totalGenerated} file(s) total (${parts.join(\" + \")})`);\n }\n}\n","import type { ToolRuleExtraFixedFile } from \"../../features/rules/tool-rule.js\";\nimport type { Feature } from \"../../types/features.js\";\nimport { getProcessorRegistryEntry } from \"../../types/processor-registry.js\";\nimport type { ToolTarget } from \"../../types/tool-targets.js\";\n\nexport type GitignoreEntryTarget = ToolTarget | \"common\";\n\nexport type GitignoreEntryTag = {\n readonly target: GitignoreEntryTarget | ReadonlyArray<GitignoreEntryTarget>;\n readonly feature: Feature | \"general\";\n readonly entry: string;\n};\n\n// Targets excluded from derivation: they don't generate project files\n// (agentsskills) or are deprecated aliases whose outputs are covered elsewhere\n// (augmentcode-legacy → augmentcode, claudecode-legacy → claudecode).\nconst TARGETS_NOT_DERIVED: ReadonlySet<string> = new Set([\n \"agentsskills\",\n \"augmentcode-legacy\",\n \"claudecode-legacy\",\n]);\n\n// Project-scope outputs that rulesync merges into rather than fully owns\n// (user-managed settings files), so they are deliberately not gitignored even\n// though a feature emits them. Most paths come straight from a tool's default\n// getSettablePaths; `.amp/settings.jsonc` (runtime probe twin of\n// `.amp/settings.json`) and `.claude/settings.local.json` (claudecode ignore\n// `fileMode: \"local\"` variant) are emitted only under non-default options.\nexport const DERIVED_PATHS_NOT_GITIGNORED: ReadonlySet<string> = new Set([\n \"**/.amp/settings.json\",\n \"**/.amp/settings.jsonc\",\n \"**/.antigravity/settings.json\",\n \"**/.claude/settings.json\",\n \"**/.claude/settings.local.json\",\n \"**/.codex/config.toml\",\n \"**/.devin/config.json\",\n \"**/.factory/settings.json\",\n \"**/.grok/config.toml\",\n \"**/.vibe/config.toml\",\n \"**/reasonix.toml\",\n \"**/.vscode/settings.json\",\n \"**/.zed/settings.json\",\n \"**/kilo.json\",\n \"**/kilo.jsonc\",\n \"**/opencode.json\",\n]);\n\nconst toPosix = (path: string): string => path.replace(/\\\\/g, \"/\");\n\nconst dirToGlob = (relativeDirPath: string): string =>\n `**/${toPosix(relativeDirPath).replace(/\\/$/, \"\")}/`;\n\nconst fileToGlob = (relativeDirPath: string | undefined, relativeFilePath: string): string => {\n const hasDir = relativeDirPath && relativeDirPath !== \".\";\n return `**/${toPosix(hasDir ? `${relativeDirPath}/${relativeFilePath}` : relativeFilePath)}`;\n};\n\nconst supportsProject = (factory: unknown): boolean => {\n if (typeof factory !== \"object\" || factory === null || !(\"meta\" in factory)) return true;\n const meta = (factory as { meta?: { supportsProject?: boolean } }).meta;\n return meta?.supportsProject !== false;\n};\n\ntype SettablePathsFn = (options?: { global?: boolean }) => unknown;\n\ntype FactoryMap = ReadonlyMap<ToolTarget, { readonly class: { getSettablePaths: unknown } }>;\n\nconst getProjectPaths = (factory: { class: { getSettablePaths: unknown } }): unknown =>\n (factory.class.getSettablePaths as SettablePathsFn)({ global: false });\n\nconst pushEntry = (\n entries: GitignoreEntryTag[],\n target: ToolTarget,\n feature: Feature,\n entry: string,\n): void => {\n entries.push({ target, feature, entry });\n};\n\nconst deriveDirEntries = (factories: FactoryMap, feature: Feature): GitignoreEntryTag[] => {\n const entries: GitignoreEntryTag[] = [];\n for (const [target, factory] of factories) {\n if (TARGETS_NOT_DERIVED.has(target)) continue;\n if (!supportsProject(factory)) continue;\n const paths = getProjectPaths(factory) as { relativeDirPath?: string };\n const dir = paths.relativeDirPath;\n if (!dir || dir === \".\") continue;\n pushEntry(entries, target, feature, dirToGlob(dir));\n }\n return entries;\n};\n\nconst deriveFileEntries = (factories: FactoryMap, feature: Feature): GitignoreEntryTag[] => {\n const entries: GitignoreEntryTag[] = [];\n for (const [target, factory] of factories) {\n if (TARGETS_NOT_DERIVED.has(target)) continue;\n if (!supportsProject(factory)) continue;\n const paths = getProjectPaths(factory) as {\n relativeDirPath?: string;\n relativeFilePath?: string;\n };\n if (!paths.relativeFilePath) continue;\n pushEntry(entries, target, feature, fileToGlob(paths.relativeDirPath, paths.relativeFilePath));\n }\n return entries;\n};\n\n// Rules have a composite shape: root/alternativeRoots are files, nonRoot is a\n// directory subtree.\nconst deriveRulesEntries = (): GitignoreEntryTag[] => {\n const entries: GitignoreEntryTag[] = [];\n const factories = getProcessorRegistryEntry(\"rules\").factory as unknown as FactoryMap;\n for (const [target, factory] of factories) {\n if (TARGETS_NOT_DERIVED.has(target)) continue;\n const paths = getProjectPaths(factory) as {\n root?: { relativeDirPath: string; relativeFilePath: string };\n alternativeRoots?: ReadonlyArray<{ relativeDirPath: string; relativeFilePath: string }>;\n nonRoot?: { relativeDirPath: string } | null;\n };\n for (const root of [paths.root, ...(paths.alternativeRoots ?? [])]) {\n if (root)\n pushEntry(\n entries,\n target,\n \"rules\",\n fileToGlob(root.relativeDirPath, root.relativeFilePath),\n );\n }\n const nonRootDir = paths.nonRoot?.relativeDirPath;\n if (nonRootDir && nonRootDir !== \".\") {\n pushEntry(entries, target, \"rules\", dirToGlob(nonRootDir));\n }\n // Extra fixed-path files a tool manages beyond root/nonRoot (e.g. Pi's\n // `.pi/APPEND_SYSTEM.md`). Derived from the same hook the RulesProcessor uses.\n const classWithExtraFiles = factory.class as {\n getExtraFixedFiles?: (options?: { global?: boolean }) => ToolRuleExtraFixedFile[];\n };\n if (classWithExtraFiles.getExtraFixedFiles) {\n for (const file of classWithExtraFiles.getExtraFixedFiles({ global: false })) {\n pushEntry(\n entries,\n target,\n \"rules\",\n fileToGlob(file.relativeDirPath, file.relativeFilePath),\n );\n }\n }\n }\n return entries;\n};\n\n// commands/skills/subagents/checks emit a directory tree; mcp/hooks/permissions/ignore\n// emit a single file; rules has a composite root+nonRoot shape.\nconst DIR_FEATURES = new Set<Feature>([\"commands\", \"skills\", \"subagents\", \"checks\"]);\nconst FILE_FEATURES = new Set<Feature>([\"mcp\", \"hooks\", \"permissions\", \"ignore\"]);\n\nconst deriveFeatureGitignoreEntries = (feature: Feature): GitignoreEntryTag[] => {\n if (feature === \"rules\") return deriveRulesEntries();\n const factory = getProcessorRegistryEntry(feature).factory as unknown as FactoryMap;\n if (DIR_FEATURES.has(feature)) return deriveDirEntries(factory, feature);\n if (FILE_FEATURES.has(feature)) return deriveFileEntries(factory, feature);\n return [];\n};\n\nconst DERIVED_FEATURES: ReadonlyArray<Feature> = [\n \"rules\",\n \"commands\",\n \"skills\",\n \"subagents\",\n \"mcp\",\n \"hooks\",\n \"permissions\",\n \"ignore\",\n \"checks\",\n];\n\n// Every project-scope output path, derived from each tool's getSettablePaths,\n// BEFORE the DERIVED_PATHS_NOT_GITIGNORED exclusion is applied. Exported so\n// tests can verify each exclusion-set path still matches a real output path.\nexport const deriveAllGitignoreEntriesUnfiltered = (): GitignoreEntryTag[] =>\n DERIVED_FEATURES.flatMap((feature) => deriveFeatureGitignoreEntries(feature));\n\n// Every gitignore entry rulesync emits, derived from each tool's getSettablePaths.\nexport const deriveAllGitignoreEntries = (): GitignoreEntryTag[] =>\n deriveAllGitignoreEntriesUnfiltered().filter(\n (tag) => !DERIVED_PATHS_NOT_GITIGNORED.has(tag.entry),\n );\n","import {\n CLAUDECODE_DIR,\n CLAUDECODE_LOCAL_RULE_FILE_NAME,\n CLAUDECODE_MEMORIES_DIR_NAME,\n CLAUDECODE_SETTINGS_LOCAL_FILE_NAME,\n} from \"../../constants/claudecode-paths.js\";\nimport { CODEXCLI_BASH_RULES_FILE_NAME, CODEXCLI_DIR } from \"../../constants/codexcli-paths.js\";\nimport { RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH } from \"../../constants/rulesync-paths.js\";\nimport {\n ALL_FEATURES_WITH_WILDCARD,\n type Feature,\n type RulesyncFeatures,\n} from \"../../types/features.js\";\nimport { ALL_TOOL_TARGETS_WITH_WILDCARD } from \"../../types/tool-targets.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport {\n deriveAllGitignoreEntries,\n type GitignoreEntryTag,\n type GitignoreEntryTarget,\n} from \"./gitignore-derive.js\";\n\nconst normalizeGitignoreEntryTargets = (\n target: GitignoreEntryTag[\"target\"],\n): ReadonlyArray<GitignoreEntryTarget> => {\n return typeof target === \"string\" ? [target] : target;\n};\n\n// Hand-maintained entries that are NOT derivable from any tool's\n// getSettablePaths, because they are not rulesync-owned generated outputs:\n// - rulesync's own meta files (`.rulesync/**`, `rulesync.local.jsonc`, the\n// `AGENTS.local.md` / `CLAUDE.local.md` local-root files, the `.aiignore`\n// un-ignore exception)\n// - third-party tool by-products rulesync never writes but gitignores as a\n// convenience (`.claude/*.lock`, `.takt/runs/`, lock files, …)\n// - the `.codexignore` ghost (codexcli has no ignore processor)\n// Everything a tool actually emits is derived below from getSettablePaths.\nexport const HAND_MAINTAINED_GITIGNORE_ENTRIES: ReadonlyArray<GitignoreEntryTag> = [\n // rulesync's own meta files (common scope).\n {\n target: \"common\",\n feature: \"general\",\n entry: `${RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH}/`,\n },\n { target: \"common\", feature: \"general\", entry: \".rulesync/rules/*.local.md\" },\n { target: \"common\", feature: \"general\", entry: \"rulesync.local.jsonc\" },\n // AGENTS.local.md is placed in common scope (not rovodev-only) so that\n // local rule files are always gitignored regardless of which targets are enabled.\n { target: \"common\", feature: \"general\", entry: \"**/AGENTS.local.md\" },\n\n // Local-root rule files: materialized outside getSettablePaths.\n { target: \"claudecode\", feature: \"rules\", entry: `**/${CLAUDECODE_LOCAL_RULE_FILE_NAME}` },\n {\n target: \"claudecode\",\n feature: \"rules\",\n entry: `**/${CLAUDECODE_DIR}/${CLAUDECODE_LOCAL_RULE_FILE_NAME}`,\n },\n\n // Third-party tool by-products rulesync gitignores but never writes itself.\n { target: \"claudecode\", feature: \"general\", entry: `**/${CLAUDECODE_DIR}/*.lock` },\n {\n target: \"claudecode\",\n feature: \"general\",\n entry: `**/${CLAUDECODE_DIR}/${CLAUDECODE_SETTINGS_LOCAL_FILE_NAME}`,\n },\n {\n target: \"claudecode\",\n feature: \"general\",\n entry: `**/${CLAUDECODE_DIR}/${CLAUDECODE_MEMORIES_DIR_NAME}/`,\n },\n { target: \"opencode\", feature: \"general\", entry: \"**/.opencode/package-lock.json\" },\n { target: \"rovodev\", feature: \"general\", entry: \"**/.rovodev/.rulesync/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/runs/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/tasks/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/.cache/\" },\n { target: \"takt\", feature: \"general\", entry: \"**/.takt/config.yaml\" },\n\n // Augment Code's legacy single-file rules path: accepted on import but never\n // generated (so not in getSettablePaths), gitignored as a convenience.\n { target: \"augmentcode\", feature: \"rules\", entry: \"**/.augment-guidelines\" },\n\n // Devin's legacy Windsurf-era workflows directory: commands are now emitted\n // onto the skills surface, but outputs generated by earlier rulesync versions\n // may still exist there, so keep them gitignored as a convenience.\n { target: \"devin\", feature: \"commands\", entry: \"**/.devin/workflows/\" },\n\n // Junie's undocumented memories directory: non-root rules are now folded\n // into the root `.junie/AGENTS.md`, but outputs generated by earlier\n // rulesync versions may still exist there, so keep them gitignored.\n { target: \"junie\", feature: \"rules\", entry: \"**/.junie/memories/\" },\n\n // Shared trees and global-scope outputs not produced via project getSettablePaths.\n { target: \"rovodev\", feature: \"skills\", entry: \"**/.agents/skills/\" },\n // The `prompts.yml` manifest is produced via `RovodevCommand.getAuxiliaryFiles`,\n // not `getSettablePaths` (only the sibling `.rovodev/prompts/` content-file\n // directory is derived automatically), so it needs a hand-maintained entry.\n { target: \"rovodev\", feature: \"commands\", entry: \"**/.rovodev/prompts.yml\" },\n { target: \"devin\", feature: \"skills\", entry: \"**/.config/devin/skills/\" },\n { target: \"copilotcli\", feature: \"subagents\", entry: \"**/.copilot/agents/\" },\n { target: \"copilotcli\", feature: \"mcp\", entry: \"**/.copilot/mcp-config.json\" },\n { target: \"copilotcli\", feature: \"hooks\", entry: \"**/.copilot/hooks/\" },\n { target: \"deepagents\", feature: \"hooks\", entry: \"**/.deepagents/hooks.json\" },\n\n // Roo aggregates subagents into a single `.roomodes` file (no settable path).\n { target: \"roo\", feature: \"subagents\", entry: \"**/.roomodes\" },\n\n // codexcli has no ignore processor; its `.codexignore` is a ghost entry.\n { target: \"codexcli\", feature: \"ignore\", entry: \"**/.codexignore\" },\n\n // Codex CLI's `rulesync.rules` bash-permission file is produced by\n // `createCodexcliBashRulesFile` in codexcli-permissions.ts. That file is\n // written outside `getSettablePaths`, so it is not derived automatically and\n // needs a hand-maintained entry. Only the single rulesync-owned file is\n // ignored: `.codex/rules/` is a general Codex rules location where users can\n // hand-author their own `*.rules` files that should stay version-controlled.\n {\n target: \"codexcli\",\n feature: \"permissions\",\n entry: `**/${CODEXCLI_DIR}/rules/${CODEXCLI_BASH_RULES_FILE_NAME}`,\n },\n];\n\nexport const GITIGNORE_ENTRY_REGISTRY: ReadonlyArray<GitignoreEntryTag> = [\n ...HAND_MAINTAINED_GITIGNORE_ENTRIES,\n\n // Every entry a tool actually emits, derived from its getSettablePaths.\n ...deriveAllGitignoreEntries(),\n\n // Keep this after ignore entries like Junie's \"**/.aiignore\" so the exception remains effective.\n { target: \"common\", feature: \"general\", entry: \"!.rulesync/.aiignore\" },\n];\n\nexport const ALL_GITIGNORE_ENTRIES: ReadonlyArray<string> = (() => {\n // The registry may register the SAME entry under multiple feature tags\n // The exported list dedupes while preserving the original insertion order.\n const seen = new Set<string>();\n const result: string[] = [];\n for (const tag of GITIGNORE_ENTRY_REGISTRY) {\n if (seen.has(tag.entry)) continue;\n seen.add(tag.entry);\n result.push(tag.entry);\n }\n return result;\n})();\n\ntype FilterGitignoreEntriesParams = {\n readonly targets?: ReadonlyArray<string>;\n readonly features?: RulesyncFeatures;\n};\n\nexport type ResolvedGitignoreEntry = {\n readonly entry: string;\n readonly target: ReadonlyArray<GitignoreEntryTarget>;\n readonly feature: Feature | \"general\";\n};\n\nconst isTargetSelected = (\n target: GitignoreEntryTag[\"target\"],\n selectedTargets: ReadonlyArray<string> | undefined,\n): boolean => {\n const targets = normalizeGitignoreEntryTargets(target);\n\n if (targets.includes(\"common\")) return true;\n if (!selectedTargets || selectedTargets.length === 0) return true;\n if (selectedTargets.includes(\"*\")) return true;\n return targets.some((candidate) => selectedTargets.includes(candidate));\n};\n\nconst getSelectedGitignoreEntryTargets = (\n target: GitignoreEntryTag[\"target\"],\n selectedTargets: ReadonlyArray<string> | undefined,\n): ReadonlyArray<GitignoreEntryTarget> => {\n const targets = normalizeGitignoreEntryTargets(target);\n\n if (targets.includes(\"common\")) return [\"common\"];\n if (!selectedTargets || selectedTargets.length === 0 || selectedTargets.includes(\"*\")) {\n return targets;\n }\n\n return targets.filter((candidate) => selectedTargets.includes(candidate));\n};\n\nconst isFeatureSelected = (\n feature: Feature | \"general\",\n features: RulesyncFeatures | undefined,\n): boolean => {\n if (feature === \"general\") return true;\n if (!features) return true;\n if (features.length === 0) return true;\n if (features.includes(\"*\")) return true;\n return features.includes(feature);\n};\n\nconst warnInvalidTargets = (targets: ReadonlyArray<string>, logger?: Logger): void => {\n const validTargets = new Set<string>(ALL_TOOL_TARGETS_WITH_WILDCARD);\n for (const target of targets) {\n if (!validTargets.has(target)) {\n logger?.warn(\n `Unknown target '${target}'. Valid targets: ${ALL_TOOL_TARGETS_WITH_WILDCARD.join(\", \")}`,\n );\n }\n }\n};\n\nconst warnInvalidFeatures = (features: RulesyncFeatures, logger?: Logger): void => {\n const validFeatures = new Set<string>(ALL_FEATURES_WITH_WILDCARD);\n const warned = new Set<string>();\n for (const feature of features) {\n if (!validFeatures.has(feature) && !warned.has(feature)) {\n warned.add(feature);\n logger?.warn(\n `Unknown feature '${feature}'. Valid features: ${ALL_FEATURES_WITH_WILDCARD.join(\", \")}`,\n );\n }\n }\n};\n\nexport const filterGitignoreEntries = (\n params?: FilterGitignoreEntriesParams & { logger?: Logger },\n): string[] => {\n return resolveGitignoreEntries(params).map((entry) => entry.entry);\n};\n\nexport const resolveGitignoreEntries = (\n params?: FilterGitignoreEntriesParams & { logger?: Logger },\n): ResolvedGitignoreEntry[] => {\n const { targets, features, logger } = params ?? {};\n\n if (targets && targets.length > 0) {\n warnInvalidTargets(targets, logger);\n }\n if (features) {\n warnInvalidFeatures(features, logger);\n }\n\n const seen = new Set<string>();\n const result: ResolvedGitignoreEntry[] = [];\n\n for (const tag of GITIGNORE_ENTRY_REGISTRY) {\n if (!isTargetSelected(tag.target, targets)) continue;\n const selectedTagTargets = getSelectedGitignoreEntryTargets(tag.target, targets);\n if (!isFeatureSelected(tag.feature, features)) continue;\n if (seen.has(tag.entry)) continue;\n seen.add(tag.entry);\n result.push({\n entry: tag.entry,\n target: selectedTagTargets,\n feature: tag.feature,\n });\n }\n\n return result;\n};\n","import { join } from \"node:path\";\n\nimport { ConfigResolver } from \"../../config/config-resolver.js\";\nimport type { Feature, GitignoreDestination, RulesyncFeatures } from \"../../types/features.js\";\nimport type { ToolTarget } from \"../../types/tool-targets.js\";\nimport { fileExists, readFileContent, writeFileContent } from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport {\n ALL_GITIGNORE_ENTRIES,\n resolveGitignoreEntries,\n type ResolvedGitignoreEntry,\n} from \"./gitignore-entries.js\";\n\n// Start / end markers that delimit the auto-generated block. Wrapping the\n// managed entries with an explicit footer lets `removeExistingRulesyncEntries`\n// strip the block deterministically instead of guessing where it ends.\nconst RULESYNC_HEADER = \"# Generated by Rulesync\";\nconst RULESYNC_FOOTER = \"# End of Rulesync\";\nconst LEGACY_RULESYNC_HEADER = \"# Generated by rulesync - AI tool configuration files\";\n\nconst isRulesyncHeader = (line: string): boolean => {\n const trimmed = line.trim();\n return trimmed === RULESYNC_HEADER || trimmed === LEGACY_RULESYNC_HEADER;\n};\n\nconst isRulesyncFooter = (line: string): boolean => {\n return line.trim() === RULESYNC_FOOTER;\n};\n\nconst isRulesyncEntry = (line: string): boolean => {\n const trimmed = line.trim();\n if (trimmed === \"\" || isRulesyncHeader(line) || isRulesyncFooter(line)) {\n return false;\n }\n return ALL_GITIGNORE_ENTRIES.includes(trimmed);\n};\n\n// Locate the footer that closes the block opened at `start - 1`. Returns -1 when\n// no footer appears before the next header (i.e. a legacy, marker-less block).\nconst findRulesyncFooterIndex = (lines: string[], start: number): number => {\n for (let index = start; index < lines.length; index++) {\n const line = lines[index] ?? \"\";\n if (isRulesyncFooter(line)) {\n return index;\n }\n if (isRulesyncHeader(line)) {\n return -1;\n }\n }\n return -1;\n};\n\n// Legacy fallback for blocks written before the footer marker existed: skip the\n// header and its following rulesync entries, stopping at two consecutive blank\n// lines or the first line that is neither blank nor a known rulesync entry.\nconst skipLegacyRulesyncBlock = (lines: string[], headerIndex: number): number => {\n let index = headerIndex + 1;\n let consecutiveEmptyLines = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n\n if (line.trim() === \"\") {\n consecutiveEmptyLines++;\n index++;\n if (consecutiveEmptyLines >= 2) {\n break;\n }\n continue;\n }\n\n if (isRulesyncEntry(line)) {\n consecutiveEmptyLines = 0;\n index++;\n continue;\n }\n\n // A non-blank, non-entry line ends the legacy block; leave it untouched.\n break;\n }\n\n return index;\n};\n\nconst removeExistingRulesyncEntries = (content: string): string => {\n const lines = content.split(\"\\n\");\n const filteredLines: string[] = [];\n let index = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n\n if (isRulesyncHeader(line)) {\n const footerIndex = findRulesyncFooterIndex(lines, index + 1);\n if (footerIndex !== -1) {\n // Marker-delimited block: drop everything from header to footer.\n index = footerIndex + 1;\n continue;\n }\n // No footer found: this is a legacy block, remove it heuristically.\n index = skipLegacyRulesyncBlock(lines, index);\n continue;\n }\n\n // Stray rulesync entries left outside a block (e.g. legacy leftovers).\n if (isRulesyncEntry(line)) {\n index++;\n continue;\n }\n\n filteredLines.push(line);\n index++;\n }\n\n let result = filteredLines.join(\"\\n\");\n\n while (result.endsWith(\"\\n\\n\")) {\n result = result.slice(0, -1);\n }\n\n return result;\n};\n\n// Collect the entries currently sitting inside rulesync-managed blocks (plus\n// stray recognized entries outside them), so the command can report which\n// previously managed paths are about to stop being gitignored.\nconst extractRulesyncManagedEntries = (content: string): string[] => {\n const lines = content.split(\"\\n\");\n const managed: string[] = [];\n let index = 0;\n\n const collectBlockLines = (start: number, end: number): void => {\n for (const blockLine of lines.slice(start, end)) {\n const trimmed = blockLine.trim();\n if (trimmed !== \"\") {\n managed.push(trimmed);\n }\n }\n };\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n\n if (isRulesyncHeader(line)) {\n const footerIndex = findRulesyncFooterIndex(lines, index + 1);\n if (footerIndex !== -1) {\n collectBlockLines(index + 1, footerIndex);\n index = footerIndex + 1;\n continue;\n }\n const legacyEnd = skipLegacyRulesyncBlock(lines, index);\n collectBlockLines(index + 1, legacyEnd);\n index = legacyEnd;\n continue;\n }\n\n if (isRulesyncEntry(line)) {\n managed.push(line.trim());\n }\n index++;\n }\n\n return managed;\n};\n\nexport type GitignoreCommandOptions = {\n readonly targets?: string[];\n readonly features?: RulesyncFeatures;\n};\n\nconst groupEntriesByDestination = ({\n entries,\n resolveDestination,\n}: {\n entries: ReadonlyArray<ResolvedGitignoreEntry>;\n resolveDestination: (target: ToolTarget, feature?: Feature | \"general\") => GitignoreDestination;\n}): { gitignore: string[]; gitattributes: string[] } => {\n const gitignore = new Set<string>();\n const gitattributes = new Set<string>();\n\n for (const entry of entries) {\n const selectedToolTargets = entry.target.filter(\n (target): target is ToolTarget => target !== \"common\",\n );\n const destinations = new Set<GitignoreDestination>();\n for (const target of selectedToolTargets) {\n if (entry.feature === \"general\") {\n destinations.add(resolveDestination(target));\n } else {\n destinations.add(resolveDestination(target, entry.feature));\n }\n }\n\n if (destinations.has(\"gitattributes\")) {\n gitattributes.add(entry.entry);\n }\n if (destinations.size === 0 || destinations.has(\"gitignore\")) {\n gitignore.add(entry.entry);\n }\n }\n\n return {\n gitignore: [...gitignore],\n gitattributes: [...gitattributes],\n };\n};\n\nexport const gitignoreCommand = async (\n logger: Logger,\n options?: GitignoreCommandOptions,\n): Promise<void> => {\n const gitignorePath = join(process.cwd(), \".gitignore\");\n const gitattributesPath = join(process.cwd(), \".gitattributes\");\n const config = await ConfigResolver.resolve({});\n\n const resolvedEntries = resolveGitignoreEntries({\n targets: options?.targets,\n features: options?.features,\n logger,\n });\n const { gitignore: gitignoreEntries, gitattributes: gitattributesEntries } =\n groupEntriesByDestination({\n entries: resolvedEntries,\n resolveDestination: (target, feature) => {\n if (feature === undefined || feature === \"general\") {\n return config.getGitignoreDestination(target);\n }\n return config.getGitignoreDestination(target, feature);\n },\n });\n\n const updateRulesyncFile = async ({\n filePath,\n entries,\n }: {\n filePath: string;\n entries: string[];\n }): Promise<{\n updated: boolean;\n alreadyExistedEntries: string[];\n entriesToAdd: string[];\n entriesRemoved: string[];\n }> => {\n let content = \"\";\n if (await fileExists(filePath)) {\n content = await readFileContent(filePath);\n }\n const cleanedContent = removeExistingRulesyncEntries(content);\n const entrySet = new Set(entries);\n const entriesRemoved = [\n ...new Set(extractRulesyncManagedEntries(content).filter((entry) => !entrySet.has(entry))),\n ];\n\n const existingEntries = new Set(\n content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && !isRulesyncHeader(line) && !isRulesyncFooter(line)),\n );\n const alreadyExistedEntries = entries.filter((entry) => existingEntries.has(entry));\n const entriesToAdd = entries.filter((entry) => !existingEntries.has(entry));\n const rulesyncBlock = [RULESYNC_HEADER, ...entries, RULESYNC_FOOTER].join(\"\\n\");\n const newContent =\n entries.length === 0\n ? cleanedContent.trim()\n ? `${cleanedContent.trimEnd()}\\n`\n : \"\"\n : cleanedContent.trim()\n ? `${cleanedContent.trimEnd()}\\n\\n${rulesyncBlock}\\n`\n : `${rulesyncBlock}\\n`;\n\n if (content === newContent) {\n return { updated: false, alreadyExistedEntries, entriesToAdd: [], entriesRemoved: [] };\n }\n await writeFileContent(filePath, newContent);\n return { updated: true, alreadyExistedEntries, entriesToAdd, entriesRemoved };\n };\n\n const gitignoreResult = await updateRulesyncFile({\n filePath: gitignorePath,\n entries: gitignoreEntries,\n });\n const gitattributesResult = await updateRulesyncFile({\n filePath: gitattributesPath,\n entries: gitattributesEntries,\n });\n\n if (!gitignoreResult.updated && !gitattributesResult.updated) {\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"entriesAdded\", []);\n logger.captureData(\"gitignorePath\", gitignorePath);\n logger.captureData(\"gitattributesPath\", gitattributesPath);\n logger.captureData(\"alreadyExisted\", [...gitignoreEntries, ...gitattributesEntries]);\n }\n logger.success(\".gitignore / .gitattributes are already up to date\");\n return;\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"entriesAdded\", [\n ...gitignoreResult.entriesToAdd,\n ...gitattributesResult.entriesToAdd,\n ]);\n logger.captureData(\"gitignorePath\", gitignorePath);\n logger.captureData(\"gitattributesPath\", gitattributesPath);\n logger.captureData(\"alreadyExisted\", [\n ...gitignoreResult.alreadyExistedEntries,\n ...gitattributesResult.alreadyExistedEntries,\n ]);\n logger.captureData(\"entriesRemoved\", gitignoreResult.entriesRemoved);\n }\n\n if (gitignoreResult.entriesRemoved.length > 0) {\n logger.warn(\n \"The following entries were removed from the rulesync-managed block in .gitignore and are no longer gitignored by rulesync:\",\n );\n for (const entry of gitignoreResult.entriesRemoved) {\n logger.warn(` ${entry}`);\n }\n logger.warn(\n \"Review these paths before committing — user-managed settings files may contain secrets.\",\n );\n }\n\n if (gitignoreResult.updated) {\n logger.success(\"Updated .gitignore with rulesync entries:\");\n } else {\n logger.success(\".gitignore is already up to date\");\n }\n for (const entry of gitignoreEntries) {\n logger.info(` ${entry}`);\n }\n if (gitattributesEntries.length > 0) {\n if (gitattributesResult.updated) {\n logger.success(\"Updated .gitattributes with rulesync entries:\");\n } else {\n logger.success(\".gitattributes is already up to date\");\n }\n for (const entry of gitattributesEntries) {\n logger.info(` ${entry}`);\n }\n }\n\n logger.info(\"\");\n logger.info(\n \"💡 If you're using Google Antigravity, note that rules, workflows, and skills won't load if they're gitignored.\",\n );\n logger.info(\" You can add the following to .git/info/exclude instead:\");\n logger.info(\" **/.agents/rules/\");\n logger.info(\" **/.agents/workflows/\");\n logger.info(\" **/.agents/skills/\");\n logger.info(\" For more details: https://github.com/dyoshikawa/rulesync/issues/981\");\n};\n","import { ConfigResolver, ConfigResolverResolveParams } from \"../../config/config-resolver.js\";\nimport { importFromTool } from \"../../lib/import.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { calculateTotalCount } from \"../../utils/result.js\";\n\n// `inputRoot` is intentionally excluded: it only affects where source rules\n// are *read from* during `generate`, and `import` does not consume them. Keeping\n// it in the option type would be misleading. Note that this avoids surfacing\n// the \"Ignoring `global: true`\" warning on direct programmatic / CLI callers;\n// users with an `inputRoot` set in their config file (e.g. `rulesync.jsonc`) may\n// still see the warning because `ConfigResolver.resolve` reads `configByFile`\n// regardless of this `Omit`. That residual warning is actionable — it tells\n// the user their config-file `inputRoot` is being ignored during `import`.\nexport type ImportOptions = Omit<\n ConfigResolverResolveParams,\n \"delete\" | \"outputRoots\" | \"inputRoot\"\n>;\n\nexport async function importCommand(logger: Logger, options: ImportOptions): Promise<void> {\n if (!options.targets) {\n throw new CLIError(\"No tools found in --targets\", ErrorCodes.IMPORT_FAILED);\n }\n\n // The CLI only provides the array form for --targets; the object form is\n // config-file-only. Defend with a runtime check so TS can narrow safely.\n if (!Array.isArray(options.targets)) {\n throw new CLIError(\n \"--targets object form is not supported on the command line\",\n ErrorCodes.IMPORT_FAILED,\n );\n }\n\n if (options.targets.length > 1) {\n throw new CLIError(\"Only one tool can be imported at a time\", ErrorCodes.IMPORT_FAILED);\n }\n\n const config = await ConfigResolver.resolve(options, { logger });\n\n const tool = config.getTargets()[0]!;\n\n logger.debug(`Importing files from ${tool}...`);\n\n const result = await importFromTool({ config, tool, logger });\n\n const totalImported = calculateTotalCount(result);\n\n if (totalImported === 0) {\n const enabledFeatures = config.getFeatures().join(\", \");\n logger.warn(`No files imported for enabled features: ${enabledFeatures}`);\n return;\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"tool\", tool);\n logger.captureData(\"features\", {\n rules: { count: result.rulesCount },\n ignore: { count: result.ignoreCount },\n mcp: { count: result.mcpCount },\n commands: { count: result.commandsCount },\n subagents: { count: result.subagentsCount },\n skills: { count: result.skillsCount },\n hooks: { count: result.hooksCount },\n permissions: { count: result.permissionsCount },\n checks: { count: result.checksCount },\n });\n logger.captureData(\"totalFiles\", totalImported);\n }\n\n const parts = [];\n if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);\n if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);\n if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);\n if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);\n if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);\n if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);\n if (result.hooksCount > 0) parts.push(`${result.hooksCount} hooks`);\n if (result.permissionsCount > 0) parts.push(`${result.permissionsCount} permissions`);\n if (result.checksCount > 0) parts.push(`${result.checksCount} checks`);\n\n logger.success(`Imported ${totalImported} file(s) total (${parts.join(\" + \")})`);\n}\n","import { join } from \"node:path\";\n\nimport { ConfigFile } from \"../config/config.js\";\nimport { SKILL_FILE_NAME } from \"../constants/general.js\";\nimport {\n RULESYNC_CONFIG_RELATIVE_FILE_PATH,\n RULESYNC_CONFIG_SCHEMA_URL,\n RULESYNC_MCP_SCHEMA_URL,\n RULESYNC_OVERVIEW_FILE_NAME,\n RULESYNC_PERMISSIONS_SCHEMA_URL,\n} from \"../constants/rulesync-paths.js\";\nimport { RulesyncCommand } from \"../features/commands/rulesync-command.js\";\nimport { RulesyncHooks } from \"../features/hooks/rulesync-hooks.js\";\nimport { RulesyncIgnore } from \"../features/ignore/rulesync-ignore.js\";\nimport { RulesyncMcp } from \"../features/mcp/rulesync-mcp.js\";\nimport { RulesyncPermissions } from \"../features/permissions/rulesync-permissions.js\";\nimport { RulesyncRule } from \"../features/rules/rulesync-rule.js\";\nimport { RulesyncSkill } from \"../features/skills/rulesync-skill.js\";\nimport { RulesyncSubagent } from \"../features/subagents/rulesync-subagent.js\";\nimport { ensureDir, fileExists, writeFileContent } from \"../utils/file.js\";\n\ntype InitFileResult = {\n created: boolean;\n path: string;\n};\n\nexport type InitResult = {\n configFile: InitFileResult;\n sampleFiles: InitFileResult[];\n};\n\n/**\n * Initialize rulesync configuration and sample files.\n * This is the core logic without CLI-specific logging.\n */\nexport async function init(): Promise<InitResult> {\n const sampleFiles = await createSampleFiles();\n const configFile = await createConfigFile();\n\n return {\n configFile,\n sampleFiles,\n };\n}\n\nasync function createConfigFile(): Promise<InitFileResult> {\n const path = RULESYNC_CONFIG_RELATIVE_FILE_PATH;\n\n if (await fileExists(path)) {\n return { created: false, path };\n }\n\n await writeFileContent(\n path,\n JSON.stringify(\n {\n $schema: RULESYNC_CONFIG_SCHEMA_URL,\n targets: [\"copilot\", \"cursor\", \"claudecode\", \"codexcli\"],\n features: [\n \"rules\",\n \"ignore\",\n \"mcp\",\n \"commands\",\n \"subagents\",\n \"skills\",\n \"hooks\",\n \"permissions\",\n ],\n outputRoots: [\".\"],\n delete: true,\n verbose: false,\n silent: false,\n global: false,\n simulateCommands: false,\n simulateSubagents: false,\n simulateSkills: false,\n gitignoreTargetsOnly: true,\n } satisfies ConfigFile,\n null,\n 2,\n ),\n );\n\n return { created: true, path };\n}\n\nasync function createSampleFiles(): Promise<InitFileResult[]> {\n const results: InitFileResult[] = [];\n\n // Sample file contents\n const sampleRuleFile = {\n filename: RULESYNC_OVERVIEW_FILE_NAME,\n content: `---\nroot: true\ntargets: [\"*\"]\ndescription: \"Project overview and general development guidelines\"\nglobs: [\"**/*\"]\n---\n\n# Project Overview\n\n## General Guidelines\n\n- Use TypeScript for all new code\n- Follow consistent naming conventions\n- Write self-documenting code with clear variable and function names\n- Prefer composition over inheritance\n- Use meaningful comments for complex business logic\n\n## Code Style\n\n- Use 2 spaces for indentation\n- Use semicolons\n- Use double quotes for strings\n- Use trailing commas in multi-line objects and arrays\n\n## Architecture Principles\n\n- Organize code by feature, not by file type\n- Keep related files close together\n- Use dependency injection for better testability\n- Implement proper error handling\n- Follow single responsibility principle\n`,\n };\n\n const sampleMcpFile = {\n filename: \"mcp.json\",\n content: `{\n \"$schema\": \"${RULESYNC_MCP_SCHEMA_URL}\",\n \"mcpServers\": {\n \"deepwiki\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.deepwiki.com/mcp\",\n \"env\": {}\n },\n \"rulesync\": {\n \"type\": \"stdio\",\n \"command\": \"pnpm\",\n \"args\": [\n \"dlx\",\n \"rulesync\",\n \"mcp\"\n ],\n \"env\": {}\n }\n }\n}\n`,\n };\n\n const sampleCommandFile = {\n filename: \"review-pr.md\",\n content: `---\ndescription: 'Review a pull request'\ntargets: [\"*\"]\n---\n\ntarget_pr = $ARGUMENTS\n\nIf target_pr is not provided, use the PR of the current branch.\n\nExecute the following in parallel:\n\n1. Check code quality and style consistency\n2. Review test coverage\n3. Verify documentation updates\n4. Check for potential bugs or security issues\n\nThen provide a summary of findings and suggestions for improvement.\n`,\n };\n\n const sampleSubagentFile = {\n filename: \"planner.md\",\n content: `---\nname: planner\ntargets: [\"*\"]\ndescription: >-\n This is the general-purpose planner. The user asks the agent to plan to\n suggest a specification, implement a new feature, refactor the codebase, or\n fix a bug. This agent can be called by the user explicitly only.\nclaudecode:\n model: inherit\n---\n\nYou are the planner for any tasks.\n\nBased on the user's instruction, create a plan while analyzing the related files. Then, report the plan in detail. You can output files to @tmp/ if needed.\n\nAttention, again, you are just the planner, so though you can read any files and run any commands for analysis, please don't write any code.\n`,\n };\n\n const sampleSkillFile = {\n dirName: \"project-context\",\n content: `---\nname: project-context\ndescription: \"Summarize the project context and key constraints\"\ntargets: [\"*\"]\n---\n\nSummarize the project goals, core constraints, and relevant dependencies.\nCall out any architecture decisions, shared conventions, and validation steps.\nKeep the summary concise and ready to reuse in future tasks.`,\n };\n\n const sampleIgnoreFile = {\n content: `credentials/\n`,\n };\n\n const sampleHooksFile = {\n content: `{\n \"version\": 1,\n \"hooks\": {\n \"postToolUse\": [\n {\n \"matcher\": \"Write|Edit\",\n \"command\": \".rulesync/hooks/format.sh\"\n }\n ]\n }\n}\n`,\n };\n\n // Keep the scaffolded defaults conservative: broad \"allow\" globs such as\n // \"git *\" or \"npm run *\" are effectively arbitrary code execution (git can run\n // commands via -c/aliases/hooks; npm run executes package.json scripts), so the\n // sample allows only a few explicit read-only commands and leaves everything\n // else to the \"*\": \"ask\" catch-all. Users can widen it as they see fit.\n const samplePermissionsFile = {\n content: `{\n \"$schema\": \"${RULESYNC_PERMISSIONS_SCHEMA_URL}\",\n \"permission\": {\n \"bash\": {\n \"git status\": \"allow\",\n \"git diff\": \"allow\",\n \"ls *\": \"allow\",\n \"rm -rf *\": \"deny\",\n \"*\": \"ask\"\n },\n \"edit\": {\n \"src/**\": \"allow\"\n },\n \"read\": {\n \".env\": \"deny\"\n }\n }\n}\n`,\n };\n\n // Get paths from settable paths\n const rulePaths = RulesyncRule.getSettablePaths();\n const mcpPaths = RulesyncMcp.getSettablePaths();\n const commandPaths = RulesyncCommand.getSettablePaths();\n const subagentPaths = RulesyncSubagent.getSettablePaths();\n const skillPaths = RulesyncSkill.getSettablePaths();\n const ignorePaths = RulesyncIgnore.getSettablePaths();\n const hooksPaths = RulesyncHooks.getSettablePaths();\n const permissionsPaths = RulesyncPermissions.getSettablePaths();\n\n // Ensure directories\n await ensureDir(rulePaths.recommended.relativeDirPath);\n await ensureDir(mcpPaths.recommended.relativeDirPath);\n await ensureDir(commandPaths.relativeDirPath);\n await ensureDir(subagentPaths.relativeDirPath);\n await ensureDir(skillPaths.relativeDirPath);\n await ensureDir(ignorePaths.recommended.relativeDirPath);\n\n // Create rule sample file\n const ruleFilepath = join(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);\n results.push(await writeIfNotExists(ruleFilepath, sampleRuleFile.content));\n\n // Create MCP sample file\n const mcpFilepath = join(\n mcpPaths.recommended.relativeDirPath,\n mcpPaths.recommended.relativeFilePath,\n );\n results.push(await writeIfNotExists(mcpFilepath, sampleMcpFile.content));\n\n // Create command sample file\n const commandFilepath = join(commandPaths.relativeDirPath, sampleCommandFile.filename);\n results.push(await writeIfNotExists(commandFilepath, sampleCommandFile.content));\n\n // Create subagent sample file\n const subagentFilepath = join(subagentPaths.relativeDirPath, sampleSubagentFile.filename);\n results.push(await writeIfNotExists(subagentFilepath, sampleSubagentFile.content));\n\n // Create skill sample file\n const skillDirPath = join(skillPaths.relativeDirPath, sampleSkillFile.dirName);\n await ensureDir(skillDirPath);\n const skillFilepath = join(skillDirPath, SKILL_FILE_NAME);\n results.push(await writeIfNotExists(skillFilepath, sampleSkillFile.content));\n\n // Create ignore sample file\n const ignoreFilepath = join(\n ignorePaths.recommended.relativeDirPath,\n ignorePaths.recommended.relativeFilePath,\n );\n results.push(await writeIfNotExists(ignoreFilepath, sampleIgnoreFile.content));\n\n // Create hooks sample file\n const hooksFilepath = join(hooksPaths.relativeDirPath, hooksPaths.relativeFilePath);\n results.push(await writeIfNotExists(hooksFilepath, sampleHooksFile.content));\n\n // Create permissions sample file\n const permissionsFilepath = join(\n permissionsPaths.relativeDirPath,\n permissionsPaths.relativeFilePath,\n );\n results.push(await writeIfNotExists(permissionsFilepath, samplePermissionsFile.content));\n\n return results;\n}\n\nasync function writeIfNotExists(path: string, content: string): Promise<InitFileResult> {\n if (await fileExists(path)) {\n return { created: false, path };\n }\n\n await writeFileContent(path, content);\n return { created: true, path };\n}\n","import { SKILL_FILE_NAME } from \"../../constants/general.js\";\nimport {\n RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n RULESYNC_HOOKS_RELATIVE_FILE_PATH,\n RULESYNC_MCP_RELATIVE_FILE_PATH,\n RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH,\n RULESYNC_RELATIVE_DIR_PATH,\n} from \"../../constants/rulesync-paths.js\";\nimport { init } from \"../../lib/init.js\";\nimport { ensureDir } from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\nexport async function initCommand(logger: Logger): Promise<void> {\n logger.debug(\"Initializing rulesync...\");\n\n await ensureDir(RULESYNC_RELATIVE_DIR_PATH);\n\n const result = await init();\n\n // Log sample file results\n const createdFiles: string[] = [];\n const skippedFiles: string[] = [];\n\n for (const file of result.sampleFiles) {\n if (file.created) {\n createdFiles.push(file.path);\n logger.success(`Created ${file.path}`);\n } else {\n skippedFiles.push(file.path);\n logger.info(`Skipped ${file.path} (already exists)`);\n }\n }\n\n // Log config file result\n if (result.configFile.created) {\n createdFiles.push(result.configFile.path);\n logger.success(`Created ${result.configFile.path}`);\n } else {\n skippedFiles.push(result.configFile.path);\n logger.info(`Skipped ${result.configFile.path} (already exists)`);\n }\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"created\", createdFiles);\n logger.captureData(\"skipped\", skippedFiles);\n }\n\n logger.success(\"rulesync initialized successfully!\");\n logger.info(\"Next steps:\");\n logger.info(\n `1. Edit ${RULESYNC_RELATIVE_DIR_PATH}/**/*.md, ${RULESYNC_RELATIVE_DIR_PATH}/skills/*/${SKILL_FILE_NAME}, ${RULESYNC_MCP_RELATIVE_FILE_PATH}, ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}, ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} and ${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}`,\n );\n logger.info(\"2. Run 'rulesync generate' to create configuration files\");\n}\n","import { join } from \"node:path\";\n\nimport { dump } from \"js-yaml\";\nimport { nonnegative, optional, refine, z } from \"zod/mini\";\n\nimport { fileExists, readFileContent, writeFileContent } from \"../../utils/file.js\";\nimport { loadYaml } from \"../../utils/yaml.js\";\n\n/**\n * Filename of the rulesync-managed apm-compatible lockfile. Rulesync uses a\n * lockfile name distinct from the upstream `apm` CLI's `apm.lock.yaml` so the\n * two tools do not fight over the same file: the schema is still the apm v1\n * lockfile format, but rulesync only reads/writes its own file.\n */\nconst APM_LOCKFILE_FILE_NAME = \"rulesync-apm.lock.yaml\";\nexport const APM_LOCKFILE_VERSION = \"1\" as const;\n\n/**\n * Shape of content_hash values that rulesync writes. Used by `--frozen`\n * integrity checks to decide whether a prior hash is comparable: any value\n * not matching this regex (e.g. written by the upstream `apm` CLI) is\n * skipped rather than throwing so that cross-tool interop works.\n */\nexport const RULESYNC_CONTENT_HASH_REGEX = /^sha256:[0-9a-f]{64}$/;\n\n/**\n * Single dependency entry in `rulesync-apm.lock.yaml`. Mirrors the subset of the\n * APM v1 lockfile schema that rulesync currently populates. Extra fields\n * from the spec (content_hash, is_dev, virtual_path, ...) are preserved\n * verbatim so that rulesync does not strip them out when re-writing a\n * lockfile produced by `apm` itself.\n */\nconst ApmLockDependencySchema = z.looseObject({\n repo_url: z.string(),\n resolved_commit: optional(\n z\n .string()\n .check(refine((v) => /^[0-9a-f]{40}$/.test(v), \"resolved_commit must be a 40-char hex SHA\")),\n ),\n resolved_ref: optional(z.string()),\n version: optional(z.string()),\n depth: z.int().check(nonnegative()),\n resolved_by: optional(z.string()),\n package_type: z.string(),\n // Intentionally loose: the upstream `apm` CLI may write content_hash values\n // that do not match the strict rulesync format. We accept any string on read\n // so that a lockfile produced by `apm` round-trips through rulesync without\n // throwing. Rulesync itself always writes values matching\n // `RULESYNC_CONTENT_HASH_REGEX`, and `--frozen` integrity checks only\n // enforce the comparison when the recorded hash matches that shape.\n content_hash: optional(z.string()),\n is_dev: optional(z.boolean()),\n deployed_files: z.array(z.string()),\n source: optional(z.string()),\n local_path: optional(z.string()),\n virtual_path: optional(z.string()),\n is_virtual: optional(z.boolean()),\n});\nexport type ApmLockDependency = z.infer<typeof ApmLockDependencySchema>;\n\nconst ApmLockSchema = z.looseObject({\n lockfile_version: z.literal(\"1\"),\n generated_at: z.string(),\n apm_version: z.string(),\n dependencies: z.array(ApmLockDependencySchema),\n mcp_servers: optional(z.array(z.string())),\n});\nexport type ApmLock = z.infer<typeof ApmLockSchema>;\n\nexport function getApmLockPath(projectRoot: string): string {\n return join(projectRoot, APM_LOCKFILE_FILE_NAME);\n}\n\n/**\n * Create an empty lockfile structure. `apm_version` is set to the rulesync\n * compatibility-marker string so downstream tooling can tell this lockfile\n * was produced by rulesync rather than the upstream `apm` CLI.\n *\n * When `existingLock` is provided, all top-level fields from that lock (e.g.\n * `mcp_servers` and any looseObject extras written by the upstream `apm`\n * CLI) are carried forward. `dependencies` is always reset to an empty array\n * and `generated_at` is refreshed; `apm_version` is overwritten by the value\n * passed in `params.apmVersion`.\n */\nexport function createEmptyApmLock(params: {\n apmVersion: string;\n existingLock?: ApmLock | null;\n}): ApmLock {\n const base = params.existingLock ? { ...params.existingLock } : {};\n return {\n ...base,\n lockfile_version: APM_LOCKFILE_VERSION,\n generated_at: new Date().toISOString(),\n apm_version: params.apmVersion,\n dependencies: [],\n };\n}\n\n/**\n * Parse `rulesync-apm.lock.yaml` content into an `ApmLock`. Returns `null` when the\n * content is absent / empty / non-YAML-object so callers can treat the lock\n * as missing. A *structurally* present lockfile that fails schema validation\n * throws a descriptive error rather than being silently dropped — silently\n * discarding a corrupt lockfile would erase previously pinned commits.\n */\nexport function parseApmLock(content: string): ApmLock | null {\n if (!content.trim()) {\n return null;\n }\n let loaded: unknown;\n try {\n loaded = loadYaml(content);\n } catch {\n return null;\n }\n if (!loaded || typeof loaded !== \"object\") {\n return null;\n }\n const parsed = ApmLockSchema.safeParse(loaded);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => ` - ${issue.path.join(\".\") || \"<root>\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid ${APM_LOCKFILE_FILE_NAME}:\\n${issues}`);\n }\n return parsed.data;\n}\n\nexport async function readApmLock(projectRoot: string): Promise<ApmLock | null> {\n const path = getApmLockPath(projectRoot);\n if (!(await fileExists(path))) {\n return null;\n }\n const content = await readFileContent(path);\n return parseApmLock(content);\n}\n\nexport async function writeApmLock(params: { projectRoot: string; lock: ApmLock }): Promise<void> {\n const path = getApmLockPath(params.projectRoot);\n const content = serializeApmLock(params.lock);\n await writeFileContent(path, content);\n}\n\nexport function serializeApmLock(lock: ApmLock): string {\n // `noRefs: true` avoids YAML anchors/aliases; `lineWidth: -1` keeps long\n // URLs on a single line so the file stays diff-friendly.\n return dump(lock, { noRefs: true, lineWidth: -1, sortKeys: false });\n}\n\n/**\n * Find the locked entry for a repo_url. GitHub routes `owner/repo` path\n * components case-insensitively, so the comparison here is case-insensitive\n * to match `apm-manifest.ts` canonicalization and avoid frozen-mode false\n * positives when users re-case their manifest.\n */\nexport function findApmLockDependency(\n lock: ApmLock,\n repoUrl: string,\n): ApmLockDependency | undefined {\n const target = repoUrl.toLowerCase();\n return lock.dependencies.find((d) => d.repo_url.toLowerCase() === target);\n}\n","import { join } from \"node:path\";\n\nimport { optional, z } from \"zod/mini\";\n\nimport { fileExists, readFileContent } from \"../../utils/file.js\";\nimport { loadYaml } from \"../../utils/yaml.js\";\n\nconst APM_MANIFEST_FILE_NAME = \"apm.yml\";\n\n/**\n * Parsed representation of a single APM `dependencies.apm` entry after\n * normalization. Every accepted input form (string shorthand, object form,\n * HTTPS URL) lands here.\n */\nexport type ApmDependency = {\n /** Canonical git URL. Always an HTTPS URL for the first iteration. */\n gitUrl: string;\n /** GitHub owner (extracted for use with the REST client). */\n owner: string;\n /** GitHub repo. */\n repo: string;\n /**\n * Optional ref (tag, branch, or commit SHA). Absent means \"resolve against\n * the repository's default branch\".\n */\n ref?: string;\n /**\n * Optional virtual sub-directory within the repository. When present the\n * install layout is rooted at this path.\n */\n path?: string;\n /**\n * Optional alias used to override the local install directory name.\n */\n alias?: string;\n};\n\nconst ApmObjectDependencySchema = z.looseObject({\n git: optional(z.string()),\n source: optional(z.string()),\n path: optional(z.string()),\n ref: optional(z.string()),\n alias: optional(z.string()),\n});\n\nconst ApmDependencyInputSchema = z.union([z.string(), ApmObjectDependencySchema]);\n\nconst ApmManifestSchema = z.looseObject({\n name: optional(z.string()),\n version: optional(z.string()),\n dependencies: optional(\n z.looseObject({\n apm: optional(z.array(ApmDependencyInputSchema)),\n }),\n ),\n});\n\nexport type ApmManifest = {\n name?: string;\n version?: string;\n dependencies: ApmDependency[];\n};\n\n/**\n * Return the absolute path to the project's `apm.yml`.\n */\nexport function getApmManifestPath(projectRoot: string): string {\n return join(projectRoot, APM_MANIFEST_FILE_NAME);\n}\n\n/**\n * True if `apm.yml` exists at the given base directory.\n */\nexport async function apmManifestExists(projectRoot: string): Promise<boolean> {\n return fileExists(getApmManifestPath(projectRoot));\n}\n\n/**\n * Parse `apm.yml` content. Throws with a descriptive error when parsing\n * or any dependency entry fails normalization.\n */\nexport function parseApmManifest(content: string): ApmManifest {\n const loaded = loadYaml(content);\n if (loaded === undefined || loaded === null) {\n return { dependencies: [] };\n }\n const parsed = ApmManifestSchema.safeParse(loaded);\n if (!parsed.success) {\n throw new Error(`Invalid apm.yml: ${parsed.error.message}`);\n }\n const raw = parsed.data;\n const rawDeps = raw.dependencies?.apm ?? [];\n const dependencies: ApmDependency[] = rawDeps.map((entry, index) =>\n normalizeDependency(entry, index),\n );\n return {\n name: raw.name,\n version: raw.version,\n dependencies,\n };\n}\n\n/**\n * Read and parse `apm.yml` from disk.\n */\nexport async function readApmManifest(projectRoot: string): Promise<ApmManifest> {\n const path = getApmManifestPath(projectRoot);\n const content = await readFileContent(path);\n return parseApmManifest(content);\n}\n\nfunction normalizeDependency(\n entry: string | z.infer<typeof ApmObjectDependencySchema>,\n index: number,\n): ApmDependency {\n if (typeof entry === \"string\") {\n return normalizeStringDependency(entry, index);\n }\n const gitUrl = entry.git ?? entry.source;\n if (!gitUrl) {\n throw new Error(\n `apm.yml dependency #${index + 1}: object form requires a \"git\" field. Received: ${JSON.stringify(entry)}.`,\n );\n }\n const parsedUrl = parseHttpsGitHubUrl(gitUrl);\n if (!parsedUrl) {\n throw new Error(\n `apm.yml dependency #${index + 1}: unsupported git URL \"${gitUrl}\". Only HTTPS GitHub URLs (https://github.com/owner/repo[.git]) are supported in this version. SSH, GitLab, Bitbucket, and other hosts are not yet supported.`,\n );\n }\n if (entry.path !== undefined) {\n validateSubPath(entry.path, index);\n }\n return {\n gitUrl: parsedUrl.gitUrl,\n owner: parsedUrl.owner,\n repo: parsedUrl.repo,\n ref: entry.ref,\n path: entry.path,\n alias: entry.alias,\n };\n}\n\n/**\n * Reject `dep.path` values that could escape the repository root or be\n * interpreted as an absolute path on the remote tree.\n */\nfunction validateSubPath(subPath: string, index: number): void {\n if (subPath === \"\" || subPath.startsWith(\"/\") || subPath.startsWith(\"\\\\\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: \"path\" must be a non-empty relative path without a leading slash. Received: ${JSON.stringify(subPath)}.`,\n );\n }\n const segments = subPath.split(/[/\\\\]/);\n if (segments.includes(\"..\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: \"path\" must not contain \"..\" segments. Received: ${JSON.stringify(subPath)}.`,\n );\n }\n}\n\nfunction normalizeStringDependency(entry: string, index: number): ApmDependency {\n const trimmed = entry.trim();\n if (!trimmed) {\n throw new Error(`apm.yml dependency #${index + 1}: entry must be a non-empty string.`);\n }\n rejectUnsupportedShorthand(trimmed, index);\n\n if (trimmed.startsWith(\"https://\")) {\n const [urlPart, refPart] = splitOnFirst(trimmed, \"#\");\n const parsed = parseHttpsGitHubUrl(urlPart);\n if (!parsed) {\n throw new Error(\n `apm.yml dependency #${index + 1}: unsupported URL \"${urlPart}\". Only HTTPS GitHub URLs (https://github.com/owner/repo[.git]) are supported in this version.`,\n );\n }\n return {\n gitUrl: parsed.gitUrl,\n owner: parsed.owner,\n repo: parsed.repo,\n ref: refPart || undefined,\n };\n }\n\n const [ownerRepo, refPart] = splitOnFirst(trimmed, \"#\");\n const slashIndex = ownerRepo.indexOf(\"/\");\n if (slashIndex === -1 || slashIndex === 0 || slashIndex === ownerRepo.length - 1) {\n throw new Error(\n `apm.yml dependency #${index + 1}: shorthand \"${entry}\" must be in the form \"owner/repo[#ref]\".`,\n );\n }\n if (ownerRepo.includes(\"/\", slashIndex + 1)) {\n throw new Error(\n `apm.yml dependency #${index + 1}: FQDN shorthand or sub-path shorthand (\"${entry}\") is not yet supported. Use the object form with an explicit \"git\" URL.`,\n );\n }\n // Canonicalize owner/repo to lower-case for case-insensitive matching.\n const owner = ownerRepo.substring(0, slashIndex).toLowerCase();\n const repo = ownerRepo.substring(slashIndex + 1).toLowerCase();\n return {\n gitUrl: `https://github.com/${owner}/${repo}.git`,\n owner,\n repo,\n ref: refPart || undefined,\n };\n}\n\nfunction rejectUnsupportedShorthand(entry: string, index: number): void {\n if (entry.startsWith(\"./\") || entry.startsWith(\"../\") || entry.startsWith(\"/\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: local path dependencies (\"${entry}\") are not yet supported by rulesync.`,\n );\n }\n if (entry.startsWith(\"git@\") || entry.startsWith(\"ssh://\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: SSH URL dependencies (\"${entry}\") are not yet supported. Use an HTTPS GitHub URL.`,\n );\n }\n if (entry.includes(\"@marketplace\")) {\n throw new Error(\n `apm.yml dependency #${index + 1}: APM marketplace dependencies (\"${entry}\") are not yet supported.`,\n );\n }\n}\n\nfunction parseHttpsGitHubUrl(url: string): { gitUrl: string; owner: string; repo: string } | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n const host = parsed.hostname.toLowerCase();\n if (host !== \"github.com\" && host !== \"www.github.com\") {\n return null;\n }\n const segments = parsed.pathname.split(\"/\").filter(Boolean);\n if (segments.length < 2) {\n return null;\n }\n const rawOwner = segments[0];\n const rawRepo = segments[1];\n if (!rawOwner || !rawRepo) {\n return null;\n }\n // GitHub treats owner/repo names case-insensitively for routing. Canonicalize\n // to lower-case so that lockfile comparisons and frozen-mode checks are not\n // tripped up by a user re-casing their manifest.\n const owner = rawOwner.toLowerCase();\n const repo = rawRepo.replace(/\\.git$/, \"\").toLowerCase();\n return {\n gitUrl: `https://github.com/${owner}/${repo}.git`,\n owner,\n repo,\n };\n}\n\nfunction splitOnFirst(input: string, separator: string): [string, string | undefined] {\n const idx = input.indexOf(separator);\n if (idx === -1) return [input, undefined];\n return [input.substring(0, idx), input.substring(idx + 1)];\n}\n","import { createHash } from \"node:crypto\";\nimport { join, posix } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport { FETCH_CONCURRENCY_LIMIT, MAX_FILE_SIZE } from \"../../constants/rulesync-paths.js\";\nimport type { GitHubFileEntry } from \"../../types/fetch.js\";\nimport { formatError } from \"../../utils/error.js\";\nimport { checkPathTraversal, removeFile, toPosixPath, writeFileContent } from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { GitHubClient, GitHubClientError, logGitHubAuthHints } from \"../github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"../github-utils.js\";\nimport {\n type ApmLock,\n type ApmLockDependency,\n createEmptyApmLock,\n findApmLockDependency,\n readApmLock,\n RULESYNC_CONTENT_HASH_REGEX,\n writeApmLock,\n} from \"./apm-lock.js\";\nimport { type ApmDependency, readApmManifest } from \"./apm-manifest.js\";\n\n/** APM compatibility marker written into `apm_version` when rulesync writes a lockfile. */\nconst RULESYNC_APM_COMPAT_VERSION = \"rulesync-compat/0.1\";\n\n/**\n * Primitives the first iteration deploys. Ordered by scan priority.\n * Each entry maps a package-relative source directory (rooted at the\n * dependency's `path` if given, else the repo root) to the on-disk\n * deployment directory. This matches the default APM layout when the\n * github-copilot host is present.\n */\nconst APM_PRIMITIVES: Array<{ sourceDir: string; deployDir: string; packageType: string }> = [\n {\n sourceDir: \".apm/instructions\",\n deployDir: \".github/instructions\",\n packageType: \"apm_package\",\n },\n {\n sourceDir: \".apm/skills\",\n deployDir: \".github/skills\",\n packageType: \"apm_package\",\n },\n];\n\nexport type ApmInstallOptions = {\n /** Force re-resolve all refs, ignoring the lockfile. */\n update?: boolean;\n /** Fail if the lockfile is missing or out of sync (for CI). */\n frozen?: boolean;\n /** GitHub token for private repositories. */\n token?: string;\n};\n\nexport type ApmInstallResult = {\n dependenciesProcessed: number;\n deployedFileCount: number;\n failedDependencyCount: number;\n};\n\n/**\n * Entry point for `rulesync install --mode apm`. Reads `apm.yml`, resolves\n * every declared APM dependency, fetches the subset of primitives rulesync\n * currently understands (Instructions and Skills), and updates `rulesync-apm.lock.yaml`.\n */\nexport async function installApm(params: {\n projectRoot: string;\n options?: ApmInstallOptions;\n logger: Logger;\n}): Promise<ApmInstallResult> {\n const { projectRoot, options = {}, logger } = params;\n\n const manifest = await readApmManifest(projectRoot);\n if (manifest.dependencies.length === 0) {\n logger.warn(\"apm.yml has no dependencies.apm entries. Nothing to install.\");\n return { dependenciesProcessed: 0, deployedFileCount: 0, failedDependencyCount: 0 };\n }\n\n const existingLock = await readApmLock(projectRoot);\n if (options.frozen) {\n assertFrozenLockCoversManifest({ existingLock, dependencies: manifest.dependencies });\n }\n\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n const newLock: ApmLock = createEmptyApmLock({\n apmVersion: existingLock?.apm_version ?? RULESYNC_APM_COMPAT_VERSION,\n existingLock,\n });\n\n // Dependencies are independent, so install them in parallel. The within-dep\n // tree walk is already rate-limited by the shared FETCH_CONCURRENCY_LIMIT\n // semaphore, so top-level parallelism is bounded naturally.\n //\n // Semantics:\n // frozen=true — any failure aborts the whole install (Promise.all\n // rejects on the first rejection).\n // frozen=false — each dep's promise resolves to a result object so that\n // one failing dep does not abort the others.\n type DepResult =\n | { status: \"ok\"; lockEntry: ApmLockDependency; deployedCount: number }\n | { status: \"failed\"; previous: ApmLockDependency | undefined };\n\n const frozen = options.frozen ?? false;\n\n const runOne = async (dep: ApmDependency): Promise<DepResult> => {\n const installed = await installDependency({\n dep,\n client,\n semaphore,\n projectRoot,\n existingLock,\n frozen,\n update: options.update ?? false,\n logger,\n });\n return {\n status: \"ok\",\n lockEntry: installed.lockEntry,\n deployedCount: installed.deployedFiles.length,\n };\n };\n\n const results: DepResult[] = frozen\n ? await Promise.all(manifest.dependencies.map(runOne))\n : await Promise.all(\n manifest.dependencies.map(async (dep): Promise<DepResult> => {\n try {\n return await runOne(dep);\n } catch (error) {\n logger.error(`Failed to install apm dependency \"${dep.gitUrl}\": ${formatError(error)}`);\n if (error instanceof GitHubClientError) {\n logGitHubAuthHints({ error, logger });\n }\n // Preserve the prior lock entry for failed deps so that a\n // transient network error does not destroy a previously pinned\n // commit SHA. We return it rather than pushing here so that the\n // post-loop pushes preserved entries in manifest order, not in\n // promise-completion order.\n const previous = existingLock\n ? findApmLockDependency(existingLock, canonicalRepoUrl(dep))\n : undefined;\n return { status: \"failed\", previous };\n }\n }),\n );\n\n let totalDeployed = 0;\n let failedCount = 0;\n // Iterate in manifest order to keep the lockfile deterministic regardless\n // of promise-completion timing.\n for (const result of results) {\n if (result.status === \"ok\") {\n newLock.dependencies.push(result.lockEntry);\n totalDeployed += result.deployedCount;\n } else {\n failedCount += 1;\n if (result.previous) {\n newLock.dependencies.push(result.previous);\n }\n }\n }\n\n // Remove files that were deployed by a previous install but are no longer\n // part of any current dependency's deployed_files. Without this, stale\n // artifacts would accumulate on disk forever as upstream content changes.\n //\n // SECURITY: `deployed_files` is only schema-validated as `z.array(z.string())`,\n // so a hostile lockfile (planted in a repo and processed by CI) could try\n // to make us `removeFile(\"../../etc/passwd\")`. We defense-in-depth guard\n // each entry: (a) reject absolute paths and `..` segments by shape, then\n // (b) run `checkPathTraversal` for the canonical check used on the write\n // path. Offending entries are skipped with a warn log rather than fatal so\n // that a single bad row cannot brick the install.\n if (existingLock) {\n await removeStaleApmFiles({ existingLock, newLock, projectRoot, logger });\n }\n\n // Always rewrite the lockfile (except under --frozen, which is a verify-only\n // mode). Even on a partially successful install we persist the union of\n // newly pinned entries and preserved previous entries so that first-ever\n // runs with mixed results still record the successful pins.\n if (!frozen) {\n newLock.generated_at = new Date().toISOString();\n await writeApmLock({ projectRoot, lock: newLock });\n if (failedCount === 0) {\n logger.debug(\"rulesync-apm.lock.yaml updated.\");\n } else {\n logger.warn(\n `rulesync-apm.lock.yaml written with partially successful installs (${failedCount} dep(s) failed).`,\n );\n }\n }\n\n return {\n dependenciesProcessed: manifest.dependencies.length,\n deployedFileCount: totalDeployed,\n failedDependencyCount: failedCount,\n };\n}\n\n/**\n * Frozen-mode validation: the lockfile must exist, cover every manifest\n * dependency, and not have drifted from any declared `ref`. Throws with\n * remediation guidance on the first failing check (preserving the original\n * order: missing-lock, missing-entries, then ref drift).\n */\nfunction assertFrozenLockCoversManifest(params: {\n existingLock: ApmLock | null;\n dependencies: ApmDependency[];\n}): asserts params is { existingLock: ApmLock; dependencies: ApmDependency[] } {\n const { existingLock, dependencies } = params;\n if (!existingLock) {\n throw new Error(\n \"Frozen install failed: rulesync-apm.lock.yaml is missing. Run 'rulesync install --mode apm' to create it.\",\n );\n }\n const missing = dependencies.filter(\n (dep) => !findApmLockDependency(existingLock, canonicalRepoUrl(dep)),\n );\n if (missing.length > 0) {\n const names = missing.map((d) => d.gitUrl).join(\", \");\n throw new Error(\n `Frozen install failed: rulesync-apm.lock.yaml is missing entries for: ${names}. Run 'rulesync install --mode apm' to update the lockfile.`,\n );\n }\n // Detect manifest drift: when the user edited `ref` in apm.yml without\n // re-running install, the locked ref no longer matches the declared one.\n // In frozen mode we refuse rather than silently install the locked SHA.\n const drifted = dependencies.filter((dep) => {\n if (dep.ref === undefined) return false;\n const locked = findApmLockDependency(existingLock, canonicalRepoUrl(dep));\n return locked?.resolved_ref !== undefined && locked.resolved_ref !== dep.ref;\n });\n if (drifted.length > 0) {\n const names = drifted\n .map((d) => {\n const locked = findApmLockDependency(existingLock, canonicalRepoUrl(d));\n return `${d.gitUrl} (manifest=${d.ref}, lock=${locked?.resolved_ref})`;\n })\n .join(\", \");\n throw new Error(\n `Frozen install failed: manifest ref does not match rulesync-apm.lock.yaml for: ${names}. Run 'rulesync install --mode apm' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Remove files that a previous install deployed but that are no longer part of\n * any current dependency's `deployed_files`. Each entry is path-traversal\n * hardened (shape check + `checkPathTraversal`) and offending rows are skipped\n * with a warn log rather than fatal.\n */\nasync function removeStaleApmFiles(params: {\n existingLock: ApmLock;\n newLock: ApmLock;\n projectRoot: string;\n logger: Logger;\n}): Promise<void> {\n const { existingLock, newLock, projectRoot, logger } = params;\n const newDeployedFiles = new Set(newLock.dependencies.flatMap((d) => d.deployed_files));\n const toDelete: string[] = [];\n for (const prev of existingLock.dependencies) {\n for (const deployed of prev.deployed_files) {\n if (!newDeployedFiles.has(deployed)) {\n toDelete.push(deployed);\n }\n }\n }\n for (const relativePath of toDelete) {\n if (posix.isAbsolute(relativePath) || relativePath.split(/[/\\\\]/).includes(\"..\")) {\n logger.warn(`Refusing to remove stale apm file with suspicious path: \"${relativePath}\".`);\n continue;\n }\n try {\n checkPathTraversal({ relativePath, intendedRootDir: projectRoot });\n } catch {\n logger.warn(`Refusing to remove stale apm file outside projectRoot: \"${relativePath}\".`);\n continue;\n }\n const absolute = join(projectRoot, relativePath);\n // `removeFile` is best-effort and swallows ENOENT, so missing files are\n // a no-op. This keeps a corrupted partial-install from blowing up here.\n await removeFile(absolute);\n logger.debug(`Removed stale apm file: ${relativePath}`);\n }\n}\n\nasync function installDependency(params: {\n dep: ApmDependency;\n client: GitHubClient;\n semaphore: Semaphore;\n projectRoot: string;\n existingLock: ApmLock | null;\n frozen: boolean;\n update: boolean;\n logger: Logger;\n}): Promise<{ lockEntry: ApmLockDependency; deployedFiles: string[] }> {\n const { dep, client, semaphore, projectRoot, existingLock, frozen, update, logger } = params;\n const repoUrl = canonicalRepoUrl(dep);\n const locked = existingLock ? findApmLockDependency(existingLock, repoUrl) : undefined;\n\n let resolvedRef: string;\n let resolvedSha: string;\n if (locked && !update && locked.resolved_commit && locked.resolved_ref) {\n resolvedRef = locked.resolved_ref;\n resolvedSha = locked.resolved_commit;\n logger.debug(`Using locked commit for ${repoUrl}: ${resolvedSha}`);\n } else {\n resolvedRef = dep.ref ?? (await client.getDefaultBranch(dep.owner, dep.repo));\n resolvedSha = await client.resolveRefToSha(dep.owner, dep.repo, resolvedRef);\n logger.debug(`Resolved ${repoUrl} ref \"${resolvedRef}\" -> ${resolvedSha}`);\n }\n\n // Collect (path, content) pairs before writing to disk. This lets us hash\n // them up-front and, under --frozen, refuse to overwrite good files with\n // tampered bytes. Under non-frozen we still write as we go for incremental\n // progress feedback on large dep trees.\n const deployed: Array<{ path: string; content: string }> = [];\n for (const primitive of APM_PRIMITIVES) {\n const remoteBase = dep.path\n ? toPosixPath(posix.join(dep.path, primitive.sourceDir))\n : primitive.sourceDir;\n const files = await listPrimitiveFiles({\n client,\n semaphore,\n owner: dep.owner,\n repo: dep.repo,\n ref: resolvedSha,\n remoteBase,\n logger,\n });\n if (files.length === 0) continue;\n\n await collectPrimitiveDeployments({\n dep,\n client,\n semaphore,\n projectRoot,\n primitive,\n remoteBase,\n files,\n resolvedSha,\n repoUrl,\n frozen,\n deployed,\n logger,\n });\n }\n\n deployed.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n const deployedFiles = deployed.map((d) => d.path);\n const contentHash = computeContentHash(deployed);\n\n assertFrozenContentHashMatches({ frozen, locked, contentHash, repoUrl, logger });\n\n // Under --frozen we deferred all writes until after the hash check passed.\n if (frozen) {\n for (const { path: deployRelative, content } of deployed) {\n await writeFileContent(join(projectRoot, deployRelative), content);\n }\n }\n\n const lockEntry: ApmLockDependency = {\n repo_url: repoUrl,\n resolved_commit: resolvedSha,\n resolved_ref: resolvedRef,\n depth: 1,\n package_type: \"apm_package\",\n content_hash: contentHash,\n deployed_files: deployedFiles,\n };\n if (dep.path) {\n lockEntry.virtual_path = dep.path;\n }\n\n logger.info(`Installed ${deployedFiles.length} file(s) from ${repoUrl}@${shortSha(resolvedSha)}`);\n\n return { lockEntry, deployedFiles };\n}\n\n/**\n * Fetch and validate the files for a single primitive directory, appending the\n * deployable (path, content) pairs to `deployed`. Oversized or out-of-bounds\n * files are skipped with a warn log; under non-frozen mode bytes are written to\n * disk as they are collected.\n */\nasync function collectPrimitiveDeployments(params: {\n dep: ApmDependency;\n client: GitHubClient;\n semaphore: Semaphore;\n projectRoot: string;\n primitive: (typeof APM_PRIMITIVES)[number];\n remoteBase: string;\n files: GitHubFileEntry[];\n resolvedSha: string;\n repoUrl: string;\n frozen: boolean;\n deployed: Array<{ path: string; content: string }>;\n logger: Logger;\n}): Promise<void> {\n const {\n dep,\n client,\n semaphore,\n projectRoot,\n primitive,\n remoteBase,\n files,\n resolvedSha,\n repoUrl,\n frozen,\n deployed,\n logger,\n } = params;\n\n for (const file of files) {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${repoUrl}: ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n const relativeToBase = posix.relative(remoteBase, toPosixPath(file.path));\n if (!relativeToBase || relativeToBase.startsWith(\"..\") || posix.isAbsolute(relativeToBase)) {\n logger.warn(`Skipping \"${file.path}\" from ${repoUrl}: resolved outside of \"${remoteBase}\".`);\n continue;\n }\n const deployRelative = toPosixPath(join(primitive.deployDir, relativeToBase));\n checkPathTraversal({\n relativePath: deployRelative,\n intendedRootDir: projectRoot,\n });\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(dep.owner, dep.repo, file.path, resolvedSha),\n );\n // The tree-listing size can lie (LFS pointers, filter-driver output),\n // so enforce the cap on the fetched bytes as well.\n const byteLength = Buffer.byteLength(content, \"utf8\");\n if (byteLength > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${repoUrl}: fetched ${(byteLength / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n deployed.push({ path: deployRelative, content });\n if (!frozen) {\n await writeFileContent(join(projectRoot, deployRelative), content);\n }\n }\n}\n\n/**\n * Verify integrity against the lockfile when running frozen and the prior\n * lock recorded a hash rulesync itself wrote. A mismatch means either the\n * upstream content moved under the same SHA (unlikely with git) or someone\n * tampered with the lockfile / deployed files. We do this *before* writing\n * anything to disk under --frozen so that tampered bytes never hit the\n * filesystem.\n *\n * If the recorded hash does not match the rulesync format (e.g. the\n * lockfile was produced by the upstream `apm` CLI which writes a different\n * shape), we skip the integrity check rather than fail — the commit SHA\n * pin is still enforced, and this preserves interop for users migrating\n * from `apm` to `rulesync install --mode apm`.\n */\nfunction assertFrozenContentHashMatches(params: {\n frozen: boolean;\n locked: ApmLockDependency | undefined;\n contentHash: string;\n repoUrl: string;\n logger: Logger;\n}): void {\n const { frozen, locked, contentHash, repoUrl, logger } = params;\n if (frozen && locked?.content_hash) {\n if (RULESYNC_CONTENT_HASH_REGEX.test(locked.content_hash)) {\n if (locked.content_hash !== contentHash) {\n throw new Error(\n `content_hash mismatch for ${repoUrl}: lock=${locked.content_hash} computed=${contentHash}. Refuse to trust the deployment under --frozen.`,\n );\n }\n } else {\n logger.debug(\n `Skipping content_hash integrity check for ${repoUrl}: recorded hash \"${locked.content_hash}\" was not written by rulesync.`,\n );\n }\n }\n}\n\n/**\n * SHA-256 over a canonical, order-independent representation of the deployed\n * files. Written into `content_hash` so that `--frozen` installs can refuse\n * to trust tampered output.\n */\nfunction computeContentHash(files: Array<{ path: string; content: string }>): string {\n const hash = createHash(\"sha256\");\n for (const { path, content } of files) {\n hash.update(path);\n hash.update(\"\\0\");\n hash.update(content);\n hash.update(\"\\0\");\n }\n return `sha256:${hash.digest(\"hex\")}`;\n}\n\nasync function listPrimitiveFiles(params: {\n client: GitHubClient;\n semaphore: Semaphore;\n owner: string;\n repo: string;\n ref: string;\n remoteBase: string;\n logger: Logger;\n}): Promise<GitHubFileEntry[]> {\n const { client, semaphore, owner, repo, ref, remoteBase, logger } = params;\n try {\n return await listDirectoryRecursive({\n client,\n owner,\n repo,\n path: remoteBase,\n ref,\n semaphore,\n });\n } catch (error) {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n logger.debug(`No ${remoteBase}/ in ${owner}/${repo}, skipping.`);\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Canonical repo_url written into the lockfile. We always use the HTTPS form\n * without a trailing `.git` so that lock files round-trip deterministically\n * regardless of whether the manifest referenced the repo with or without\n * the suffix.\n */\nfunction canonicalRepoUrl(dep: ApmDependency): string {\n return `https://github.com/${dep.owner}/${dep.repo}`;\n}\n\nfunction shortSha(sha: string): string {\n return sha.substring(0, 7);\n}\n","import { dump } from \"js-yaml\";\n\nimport { loadYaml } from \"../../utils/yaml.js\";\n\nconst FRONTMATTER_FENCE = \"---\";\n\n/**\n * Parses YAML frontmatter at the head of a SKILL.md, sets/overwrites the\n * three provenance keys (`source`, `repository`, `ref`), and re-serializes.\n *\n * If the file has no frontmatter block, a fresh one is prepended with only\n * the provenance keys + the original body. All other existing frontmatter\n * keys are preserved verbatim (the merge is a shallow object spread on the\n * loaded YAML).\n *\n * Throws `Error(\"invalid frontmatter\")` when an `---` fenced block exists\n * but its body is not a YAML object (e.g. malformed YAML, or a list/scalar\n * at the top level). Callers may choose to fall back to \"prepend fresh\" on\n * this error, but the function itself does not silently rewrite — silently\n * dropping a corrupted frontmatter could destroy user metadata.\n */\nexport function injectSourceMetadata(params: {\n content: string;\n source: string;\n repository: string;\n ref: string;\n}): string {\n const { content, source, repository, ref } = params;\n const provenance = { source, repository, ref };\n\n // Detect the opening fence in both LF (`---\\n`) and CRLF (`---\\r\\n`) forms.\n // SKILL.md files authored on Windows or by editors that preserve CRLF must\n // round-trip cleanly — without this branch the existing frontmatter would\n // be buried inside a fresh provenance block on the first install.\n let openFenceLen: number;\n if (content.startsWith(`${FRONTMATTER_FENCE}\\r\\n`)) {\n openFenceLen = 5;\n } else if (content.startsWith(`${FRONTMATTER_FENCE}\\n`)) {\n openFenceLen = 4;\n } else if (content === FRONTMATTER_FENCE) {\n openFenceLen = 3;\n } else {\n // No frontmatter block. Prepend a fresh one with just the provenance keys.\n const yaml = dump(provenance, { noRefs: true, lineWidth: -1, sortKeys: false });\n return `${FRONTMATTER_FENCE}\\n${yaml}${FRONTMATTER_FENCE}\\n${content}`;\n }\n\n // Body starts immediately after the opening fence.\n const afterOpen = content.substring(openFenceLen);\n\n // Closing fence forms we accept:\n // - `---` immediately at the start of the body (i.e. `---\\n---\\n...`,\n // which yields an empty frontmatter block).\n // - `\\n---` followed by a newline OR end-of-file (the trailing newline\n // after the closing `---` is optional so the fence may sit at EOF).\n let fmBody: string;\n let rest: string;\n if (afterOpen.startsWith(\"---\\n\") || afterOpen.startsWith(\"---\\r\\n\") || afterOpen === \"---\") {\n fmBody = \"\";\n const fenceLen = afterOpen.startsWith(\"---\\r\\n\") ? 5 : afterOpen === \"---\" ? 3 : 4;\n rest = afterOpen.substring(fenceLen);\n } else {\n const match = /\\n---(\\r?\\n|$)/.exec(afterOpen);\n if (!match) {\n // The file starts with `---\\n` but there is no closing `---` line. We\n // refuse to guess where the frontmatter ends; treat as invalid so the\n // caller can decide whether to fall back.\n throw new Error(\"invalid frontmatter\");\n }\n fmBody = afterOpen.substring(0, match.index);\n rest = afterOpen.substring(match.index + match[0].length);\n }\n\n let loaded: unknown;\n try {\n loaded = loadYaml(fmBody);\n } catch {\n throw new Error(\"invalid frontmatter\");\n }\n\n if (loaded === null || loaded === undefined) {\n // Empty frontmatter block (`---\\n---\\n...`). Use only provenance.\n const yaml = dump(provenance, { noRefs: true, lineWidth: -1, sortKeys: false });\n return `${FRONTMATTER_FENCE}\\n${yaml}${FRONTMATTER_FENCE}\\n${rest}`;\n }\n if (typeof loaded !== \"object\" || Array.isArray(loaded)) {\n throw new Error(\"invalid frontmatter\");\n }\n\n // Shallow merge: existing keys preserved, provenance keys overwritten.\n const existing = loaded as Record<string, unknown>;\n const merged: Record<string, unknown> = {\n ...existing,\n ...provenance,\n };\n const yaml = dump(merged, { noRefs: true, lineWidth: -1, sortKeys: false });\n return `${FRONTMATTER_FENCE}\\n${yaml}${FRONTMATTER_FENCE}\\n${rest}`;\n}\n","import { join } from \"node:path\";\n\nimport { dump } from \"js-yaml\";\nimport { optional, refine, z } from \"zod/mini\";\n\nimport { fileExists, readFileContent, writeFileContent } from \"../../utils/file.js\";\nimport { loadYaml } from \"../../utils/yaml.js\";\n\n/**\n * Filename of the rulesync-managed gh-skill-compatible lockfile. Distinct\n * from the rulesync sources lockfile (`rulesync.lock`) and from the\n * apm-mode lockfile (`rulesync-apm.lock.yaml`) so the three install modes\n * never fight over the same file.\n */\nconst GH_LOCKFILE_FILE_NAME = \"rulesync-gh.lock.yaml\";\nexport const GH_LOCKFILE_VERSION = \"1\" as const;\n\n/**\n * Shape of content_hash values that rulesync writes for gh installs. Same\n * format as the apm-mode hash so callers can reuse the integrity check\n * conventions; under `--frozen` only values matching this regex are\n * considered comparable.\n */\nexport const RULESYNC_CONTENT_HASH_REGEX = /^sha256:[0-9a-f]{64}$/;\n\nconst ScopeSchema = z.enum([\"project\", \"user\"]);\n\n/**\n * Single installation entry in `rulesync-gh.lock.yaml`. Each entry pins one\n * skill from one source under one (agent, scope) pair — matching the gh CLI\n * model where `gh skill install` deploys exactly one skill at a time.\n */\nconst GhLockInstallationSchema = z.looseObject({\n source: z.string(),\n owner: z.string(),\n repo: z.string(),\n agent: z.string(),\n scope: ScopeSchema,\n skill: z.string(),\n requested_ref: optional(z.string()),\n resolved_ref: z.string(),\n resolved_commit: z\n .string()\n .check(refine((v) => /^[0-9a-f]{40}$/.test(v), \"resolved_commit must be a 40-char hex SHA\")),\n install_dir: z.string(),\n deployed_files: z.array(z.string()),\n content_hash: optional(z.string()),\n});\nexport type GhLockInstallation = z.infer<typeof GhLockInstallationSchema>;\n\nconst GhLockSchema = z.looseObject({\n lockfile_version: z.literal(\"1\"),\n generated_at: z.string(),\n installations: z.array(GhLockInstallationSchema),\n});\nexport type GhLock = z.infer<typeof GhLockSchema>;\n\nexport function getGhLockPath(projectRoot: string): string {\n return join(projectRoot, GH_LOCKFILE_FILE_NAME);\n}\n\n/**\n * Create an empty gh lockfile structure. When `existingLock` is provided,\n * top-level looseObject extras are carried forward so unknown fields (added\n * by future tools or other lockfile producers) round-trip cleanly.\n */\nexport function createEmptyGhLock(params?: { existingLock?: GhLock | null }): GhLock {\n const base = params?.existingLock ? { ...params.existingLock } : {};\n return {\n ...base,\n lockfile_version: GH_LOCKFILE_VERSION,\n generated_at: new Date().toISOString(),\n installations: [],\n };\n}\n\n/**\n * Parse `rulesync-gh.lock.yaml` content into a `GhLock`. Returns `null` for\n * empty / non-YAML-object content so callers can treat the lockfile as\n * missing. A *structurally* present lockfile that fails schema validation\n * throws, rather than silently dropping previously pinned entries.\n */\nexport function parseGhLock(content: string): GhLock | null {\n if (!content.trim()) {\n return null;\n }\n let loaded: unknown;\n try {\n loaded = loadYaml(content);\n } catch {\n return null;\n }\n if (!loaded || typeof loaded !== \"object\") {\n return null;\n }\n const parsed = GhLockSchema.safeParse(loaded);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => ` - ${issue.path.join(\".\") || \"<root>\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid ${GH_LOCKFILE_FILE_NAME}:\\n${issues}`);\n }\n return parsed.data;\n}\n\nexport async function readGhLock(projectRoot: string): Promise<GhLock | null> {\n const path = getGhLockPath(projectRoot);\n if (!(await fileExists(path))) {\n return null;\n }\n const content = await readFileContent(path);\n return parseGhLock(content);\n}\n\nexport async function writeGhLock(params: { projectRoot: string; lock: GhLock }): Promise<void> {\n const path = getGhLockPath(params.projectRoot);\n const content = serializeGhLock(params.lock);\n await writeFileContent(path, content);\n}\n\nexport function serializeGhLock(lock: GhLock): string {\n // `noRefs: true` avoids YAML anchors/aliases; `lineWidth: -1` keeps long\n // URLs and sha values on a single line so the file stays diff-friendly.\n return dump(lock, { noRefs: true, lineWidth: -1, sortKeys: false });\n}\n\n/**\n * Find the locked installation for a given (source, agent, scope, skill)\n * tuple. Source is matched case-insensitively because GitHub routes\n * `owner/repo` paths case-insensitively.\n */\nexport function findGhLockInstallation(\n lock: GhLock,\n params: { source: string; agent: string; scope: \"project\" | \"user\"; skill: string },\n): GhLockInstallation | undefined {\n const target = params.source.toLowerCase();\n return lock.installations.find(\n (i) =>\n i.source.toLowerCase() === target &&\n i.agent === params.agent &&\n i.scope === params.scope &&\n i.skill === params.skill,\n );\n}\n","import { join } from \"node:path\";\n\nimport { CLAUDECODE_SKILLS_DIR_PATH } from \"../../constants/claudecode-paths.js\";\nimport { getHomeDirectory } from \"../../utils/file.js\";\n\n/**\n * Agents recognized by `--mode gh`. Mirrors the agent list documented for\n * `gh skill install`. The same skill content can be deployed under multiple\n * agent-specific directories simultaneously, one entry per `(agent, scope)`\n * pair in `rulesync.jsonc`.\n */\nexport const GH_AGENTS = [\n \"github-copilot\",\n \"claude-code\",\n \"cursor\",\n \"codex\",\n \"gemini\",\n \"antigravity\",\n] as const;\nexport type GhAgent = (typeof GH_AGENTS)[number];\n\nexport type GhScope = \"project\" | \"user\";\n\n/**\n * Resolve the absolute install directory for a given agent + scope, matching\n * the layout expected by `gh skill install`.\n *\n * Project scope writes inside `projectRoot`. The `github-copilot` agent uses the\n * shared `.agents/skills` directory (the host-agnostic project layout); other\n * agents that share that location (cursor, codex, gemini, antigravity) write\n * to `.agents/skills` for project scope and to their own `.<tool>/skills`\n * directory for user scope. Claude Code is the exception: project and user\n * scope both use `.claude/skills`, just rooted at `projectRoot` vs the home\n * directory respectively.\n */\nexport function resolveGhInstallDir(params: {\n agent: GhAgent;\n scope: GhScope;\n projectRoot: string;\n}): string {\n const { agent, scope, projectRoot } = params;\n const home = scope === \"user\" ? getHomeDirectory() : projectRoot;\n const relative = relativeInstallDirFor({ agent, scope });\n return join(home, relative);\n}\n\n/**\n * Returns the install directory relative to its scope root (projectRoot for\n * project scope, home for user scope). Exposed separately so the lockfile can\n * record the same canonical relative path it deploys to.\n */\nexport function relativeInstallDirFor(params: { agent: GhAgent; scope: GhScope }): string {\n const { agent, scope } = params;\n if (scope === \"project\") {\n if (agent === \"claude-code\") {\n return CLAUDECODE_SKILLS_DIR_PATH;\n }\n // github-copilot and the rest share the shared project layout.\n return join(\".agents\", \"skills\");\n }\n // user scope\n switch (agent) {\n case \"github-copilot\":\n return join(\".copilot\", \"skills\");\n case \"claude-code\":\n return CLAUDECODE_SKILLS_DIR_PATH;\n case \"cursor\":\n return join(\".cursor\", \"skills\");\n case \"codex\":\n return join(\".agents\", \"skills\");\n case \"gemini\":\n return join(\".gemini\", \"skills\");\n case \"antigravity\":\n return join(\".gemini\", \"antigravity\", \"skills\");\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { basename, join, posix } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport type { SourceEntry } from \"../../config/config.js\";\nimport { FETCH_CONCURRENCY_LIMIT, MAX_FILE_SIZE } from \"../../constants/rulesync-paths.js\";\nimport { formatError } from \"../../utils/error.js\";\nimport {\n checkPathTraversal,\n getHomeDirectory,\n removeFile,\n toPosixPath,\n writeFileContent,\n} from \"../../utils/file.js\";\nimport type { Logger } from \"../../utils/logger.js\";\nimport { GitHubClient, GitHubClientError, logGitHubAuthHints } from \"../github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"../github-utils.js\";\nimport { parseSource } from \"../source-parser.js\";\nimport { injectSourceMetadata } from \"./gh-frontmatter.js\";\nimport {\n createEmptyGhLock,\n findGhLockInstallation,\n type GhLock,\n type GhLockInstallation,\n readGhLock,\n RULESYNC_CONTENT_HASH_REGEX,\n writeGhLock,\n} from \"./gh-lock.js\";\nimport { type GhAgent, GH_AGENTS, type GhScope, relativeInstallDirFor } from \"./gh-paths.js\";\n\nconst SKILLS_REMOTE_DIR = \"skills\";\nconst SKILL_FILE_NAME = \"SKILL.md\";\n\nexport type GhInstallOptions = {\n /** Force re-resolve all refs, ignoring the lockfile. */\n update?: boolean;\n /** Fail if the lockfile is missing or out of sync (for CI). */\n frozen?: boolean;\n /** GitHub token for private repositories. */\n token?: string;\n};\n\nexport type GhInstallResult = {\n sourcesProcessed: number;\n installedSkillCount: number;\n failedSourceCount: number;\n};\n\ntype ResolvedSource = {\n entry: SourceEntry;\n owner: string;\n repo: string;\n ref?: string;\n agent: GhAgent;\n scope: GhScope;\n};\n\ntype DeployedFile = {\n /** Relative POSIX path under the install dir's scope root. Recorded in the lockfile. */\n relativeToScopeRoot: string;\n /** Absolute on-disk path where the bytes are written. */\n absolutePath: string;\n content: string;\n};\n\ntype SkillInstallation = {\n installation: GhLockInstallation;\n deployed: DeployedFile[];\n};\n\ntype SourceResult =\n | { status: \"ok\"; installations: SkillInstallation[] }\n | { status: \"failed\"; preserved: GhLockInstallation[] };\n\n/**\n * Entry point for `rulesync install --mode gh`. Reads `sources` from\n * `rulesync.jsonc`, resolves each one against the GitHub API, and deploys\n * each discovered `skills/<name>/` tree under the agent-specific install\n * directory recorded by `resolveGhInstallDir`. Updates `rulesync-gh.lock.yaml`\n * to pin commits and per-skill content hashes.\n */\nexport async function installGh(params: {\n projectRoot: string;\n sources: SourceEntry[];\n options?: GhInstallOptions;\n logger: Logger;\n}): Promise<GhInstallResult> {\n const { projectRoot, sources, options = {}, logger } = params;\n\n if (sources.length === 0) {\n return { sourcesProcessed: 0, installedSkillCount: 0, failedSourceCount: 0 };\n }\n\n // Pre-resolve every source's owner/repo + agent/scope defaults so the\n // frozen-mode coverage check below has a stable view of what installations\n // are required. We do not contact the API yet — that happens per-source.\n const resolvedSources: ResolvedSource[] = sources.map(resolveGhSource);\n\n const existingLock = await readGhLock(projectRoot);\n const frozen = options.frozen ?? false;\n const update = options.update ?? false;\n\n if (frozen && !existingLock) {\n throw new Error(\n \"Frozen install failed: rulesync-gh.lock.yaml is missing. Run 'rulesync install --mode gh' to create it.\",\n );\n }\n\n if (frozen && existingLock) {\n assertFrozenLockCoversSources({ existingLock, resolvedSources });\n }\n\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n\n const newLock: GhLock = createEmptyGhLock({ existingLock });\n\n const runOne = async (rs: ResolvedSource): Promise<SourceResult> => {\n const installations = await installSource({\n rs,\n client,\n semaphore,\n projectRoot,\n existingLock,\n frozen,\n update,\n logger,\n });\n return { status: \"ok\", installations };\n };\n\n const results: SourceResult[] = frozen\n ? await Promise.all(resolvedSources.map(runOne))\n : await Promise.all(\n resolvedSources.map(async (rs): Promise<SourceResult> => {\n try {\n return await runOne(rs);\n } catch (error) {\n logger.error(`Failed to install gh source \"${rs.entry.source}\": ${formatError(error)}`);\n if (error instanceof GitHubClientError) {\n logGitHubAuthHints({ error, logger });\n }\n // Preserve all prior installations for this source so that a\n // transient error does not erase previously pinned commit SHAs.\n const preserved = existingLock\n ? existingLock.installations.filter(\n (i) => i.source.toLowerCase() === rs.entry.source.toLowerCase(),\n )\n : [];\n return { status: \"failed\", preserved };\n }\n }),\n );\n\n if (frozen) {\n await writeDeferredFrozenFiles(results);\n }\n\n const { totalInstalled, failedCount } = aggregateSourceResults({ results, newLock });\n\n // Stale-file cleanup. Same hardening shape as apm-install.\n if (existingLock) {\n await removeStaleGhFiles({ existingLock, newLock, projectRoot, logger });\n }\n\n if (!frozen) {\n newLock.generated_at = new Date().toISOString();\n await writeGhLock({ projectRoot, lock: newLock });\n if (failedCount === 0) {\n logger.debug(\"rulesync-gh.lock.yaml updated.\");\n } else {\n logger.warn(\n `rulesync-gh.lock.yaml written with partially successful installs (${failedCount} source(s) failed).`,\n );\n }\n }\n\n return {\n sourcesProcessed: sources.length,\n installedSkillCount: totalInstalled,\n failedSourceCount: failedCount,\n };\n}\n\n/**\n * Validate and normalize a single declared source into a ResolvedSource without\n * contacting the API. Rejects non-GitHub providers and the gh-unsupported\n * `transport`/`path` fields, and applies the agent/scope defaults.\n */\nfunction resolveGhSource(entry: SourceEntry): ResolvedSource {\n const parsed = parseSource(entry.source);\n if (parsed.provider !== \"github\") {\n throw new Error(\n `--mode gh only supports GitHub sources. \"${entry.source}\" resolves to provider \"${parsed.provider}\".`,\n );\n }\n // gh mode does not honor `transport` or `path` from the SourceEntry —\n // both are rulesync-mode-only concepts. Silently dropping them would\n // surprise users migrating from --mode rulesync, so reject up-front\n // with a message that names the offending field.\n if (entry.transport !== undefined && entry.transport !== \"github\") {\n throw new Error(\n `--mode gh: field \"transport\" is not supported (got \"${entry.transport}\" for source \"${entry.source}\"). Drop the field or switch to --mode rulesync.`,\n );\n }\n if (entry.path !== undefined) {\n throw new Error(\n `--mode gh: field \"path\" is not supported for source \"${entry.source}\". The remote layout is fixed to \"skills/<name>/SKILL.md\".`,\n );\n }\n const agent = entry.agent ?? \"github-copilot\";\n if (!GH_AGENTS.includes(agent)) {\n throw new Error(\n `--mode gh: unknown agent \"${agent}\" for source \"${entry.source}\". Valid agents: ${GH_AGENTS.join(\", \")}.`,\n );\n }\n const scope: GhScope = entry.scope ?? \"project\";\n return {\n entry,\n owner: parsed.owner,\n repo: parsed.repo,\n ref: entry.ref ?? parsed.ref,\n agent,\n scope,\n };\n}\n\n/**\n * Frozen mode: per-source coverage check plus `ref` drift detection. A\n * brand-new source (no installations at all in the lock) must fail before we\n * contact the GitHub API — both to save quota and to prevent in-flight\n * Promise.all siblings from writing files when another source is going to\n * throw. Per-skill coverage is enforced lazily inside installSource, since that\n * requires API discovery to know which skills exist remotely.\n */\nfunction assertFrozenLockCoversSources(params: {\n existingLock: GhLock;\n resolvedSources: ResolvedSource[];\n}): void {\n const { existingLock, resolvedSources } = params;\n const uncovered: string[] = [];\n for (const rs of resolvedSources) {\n const hasAny = existingLock.installations.some(\n (i) =>\n i.source.toLowerCase() === rs.entry.source.toLowerCase() &&\n i.agent === rs.agent &&\n i.scope === rs.scope,\n );\n if (!hasAny) {\n uncovered.push(`${rs.entry.source} (agent=${rs.agent}, scope=${rs.scope})`);\n }\n }\n if (uncovered.length > 0) {\n throw new Error(\n `Frozen install failed: rulesync-gh.lock.yaml is missing entries for: ${uncovered.join(\", \")}. Run 'rulesync install --mode gh' to update the lockfile.`,\n );\n }\n\n // Detect manifest drift on `ref`: when the user edited `ref` in\n // rulesync.jsonc without re-running install, refuse rather than\n // silently install the locked SHA against a different declared ref.\n const drifted: string[] = [];\n for (const rs of resolvedSources) {\n if (!rs.ref) continue;\n const matches = existingLock.installations.filter(\n (i) => i.source.toLowerCase() === rs.entry.source.toLowerCase(),\n );\n for (const m of matches) {\n if (m.requested_ref !== undefined && m.requested_ref !== rs.ref) {\n drifted.push(`${rs.entry.source} (manifest=${rs.ref}, lock=${m.requested_ref})`);\n break;\n }\n }\n }\n if (drifted.length > 0) {\n throw new Error(\n `Frozen install failed: manifest ref does not match rulesync-gh.lock.yaml for: ${drifted.join(\", \")}. Run 'rulesync install --mode gh' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Frozen-mode deferred writes. `installSource` never touches the disk under\n * --frozen — every write lands here, only after Promise.all has resolved\n * successfully for every source. Without this gate, source A could finish\n * writing its bytes before source B's coverage / integrity check throws,\n * leaving the working tree in a partially-frozen state despite the install\n * reporting failure.\n */\nasync function writeDeferredFrozenFiles(results: SourceResult[]): Promise<void> {\n for (const result of results) {\n if (result.status !== \"ok\") continue;\n for (const inst of result.installations) {\n for (const d of inst.deployed) {\n await writeFileContent(d.absolutePath, d.content);\n }\n }\n }\n}\n\n/**\n * Push each source result's installations (or preserved prior entries on\n * failure) into the new lock, returning the installed and failed counts.\n */\nfunction aggregateSourceResults(params: { results: SourceResult[]; newLock: GhLock }): {\n totalInstalled: number;\n failedCount: number;\n} {\n const { results, newLock } = params;\n let totalInstalled = 0;\n let failedCount = 0;\n for (const result of results) {\n if (result.status === \"ok\") {\n for (const inst of result.installations) {\n newLock.installations.push(inst.installation);\n }\n totalInstalled += result.installations.length;\n } else {\n failedCount += 1;\n for (const preserved of result.preserved) {\n newLock.installations.push(preserved);\n }\n }\n }\n return { totalInstalled, failedCount };\n}\n\n/**\n * Remove files deployed by a previous install that are no longer part of any\n * current installation, keyed by (scope, path) so identically-named files under\n * different scope roots are not conflated.\n */\nasync function removeStaleGhFiles(params: {\n existingLock: GhLock;\n newLock: GhLock;\n projectRoot: string;\n logger: Logger;\n}): Promise<void> {\n const { existingLock, newLock, projectRoot, logger } = params;\n const newDeployed = new Set<string>();\n for (const inst of newLock.installations) {\n for (const file of inst.deployed_files) {\n // Key by (scope, path) so a file in `<home>/.claude/skills/foo` and a\n // file at `<base>/.claude/skills/foo` are not conflated.\n newDeployed.add(`${inst.scope}::${file}`);\n }\n }\n for (const prev of existingLock.installations) {\n for (const deployed of prev.deployed_files) {\n const key = `${prev.scope}::${deployed}`;\n if (newDeployed.has(key)) continue;\n await removeStaleFile({\n relativePath: deployed,\n scope: prev.scope === \"user\" ? \"user\" : \"project\",\n projectRoot,\n logger,\n });\n }\n }\n}\n\nasync function installSource(params: {\n rs: ResolvedSource;\n client: GitHubClient;\n semaphore: Semaphore;\n projectRoot: string;\n existingLock: GhLock | null;\n frozen: boolean;\n update: boolean;\n logger: Logger;\n}): Promise<SkillInstallation[]> {\n const { rs, client, semaphore, projectRoot, existingLock, frozen, update, logger } = params;\n const { entry, owner, repo, agent, scope } = rs;\n const sourceKey = entry.source;\n\n const { resolvedRef, resolvedSha, usedTag } = await resolveGhRef({\n rs,\n client,\n owner,\n repo,\n sourceKey,\n logger,\n });\n\n // Discover skills under `skills/`.\n const validatedSkills = await discoverValidatedSkills({\n client,\n semaphore,\n owner,\n repo,\n resolvedSha,\n sourceKey,\n logger,\n });\n if (validatedSkills === null) {\n return [];\n }\n\n // Apply the explicit skill filter when provided.\n const selected = selectSkills({ validatedSkills, entry, sourceKey, logger });\n\n // Frozen-mode coverage check (per-skill). Only enforceable now that we know\n // the requested skill set.\n if (frozen && existingLock) {\n assertFrozenSkillCoverage({ selected, existingLock, sourceKey, agent, scope });\n }\n\n const results: SkillInstallation[] = [];\n const installRelDir = relativeInstallDirFor({ agent, scope });\n const scopeRoot = scope === \"user\" ? getHomeDirectory() : projectRoot;\n\n // Source URL recorded in injected frontmatter. Mirrors the canonical form\n // used by `gh skill install`.\n const sourceUrl = `https://github.com/${owner}/${repo}`;\n const repository = `${owner}/${repo}`;\n // gh records the *resolved* ref (the tag name when one was used, else the\n // commit SHA) into the SKILL.md frontmatter so the deployed file has a\n // human-readable provenance hint.\n const provenanceRef = usedTag ? resolvedRef : resolvedSha;\n\n for (const sk of selected) {\n const locked =\n existingLock && !update\n ? findGhLockInstallation(existingLock, {\n source: sourceKey,\n agent,\n scope,\n skill: sk.name,\n })\n : undefined;\n\n // Recursively list this skill's tree.\n const allFiles = await listDirectoryRecursive({\n client,\n owner,\n repo,\n path: sk.path,\n ref: resolvedSha,\n semaphore,\n });\n\n const deployed = await buildSkillDeployment({\n sk,\n allFiles,\n client,\n semaphore,\n owner,\n repo,\n resolvedSha,\n installRelDir,\n scopeRoot,\n sourceUrl,\n repository,\n provenanceRef,\n sourceKey,\n frozen,\n logger,\n });\n\n deployed.sort((a, b) =>\n a.relativeToScopeRoot < b.relativeToScopeRoot\n ? -1\n : a.relativeToScopeRoot > b.relativeToScopeRoot\n ? 1\n : 0,\n );\n const deployedFiles = deployed.map((d) => d.relativeToScopeRoot);\n const contentHash = computeContentHash(deployed);\n\n assertFrozenSkillIntegrity({\n frozen,\n locked,\n contentHash,\n sourceKey,\n skillName: sk.name,\n agent,\n scope,\n logger,\n });\n\n // Under --frozen we deliberately do NOT write here even after the\n // integrity check passes. Writes are deferred to the top-level installGh\n // so that a sibling source failing its check cannot leave partial bytes\n // on disk from a peer that already passed.\n const installation: GhLockInstallation = {\n source: sourceKey,\n owner,\n repo,\n agent,\n scope,\n skill: sk.name,\n resolved_ref: resolvedRef,\n resolved_commit: resolvedSha,\n install_dir: toPosixPath(installRelDir),\n deployed_files: deployedFiles,\n content_hash: contentHash,\n };\n if (rs.ref !== undefined) {\n installation.requested_ref = rs.ref;\n }\n results.push({ installation, deployed });\n\n logger.info(\n `Installed gh skill \"${sk.name}\" from ${sourceKey} (agent=${agent}, scope=${scope}, ref=${resolvedRef})`,\n );\n }\n\n return results;\n}\n\n/**\n * Resolve the ref for a gh source. Order: explicit `entry.ref`, then the latest\n * release's tag, then the default branch (when the repo has no releases).\n * Returns the resolved ref, its commit SHA, and whether a release tag was used.\n */\nasync function resolveGhRef(params: {\n rs: ResolvedSource;\n client: GitHubClient;\n owner: string;\n repo: string;\n sourceKey: string;\n logger: Logger;\n}): Promise<{ resolvedRef: string; resolvedSha: string; usedTag: boolean }> {\n const { rs, client, owner, repo, sourceKey, logger } = params;\n let resolvedRef: string;\n let usedTag = false;\n if (rs.ref) {\n resolvedRef = rs.ref;\n } else {\n try {\n const release = await client.getLatestRelease(owner, repo);\n resolvedRef = release.tag_name;\n usedTag = true;\n } catch (error) {\n // gh's behavior: when a repo has no releases, getLatestRelease returns\n // 404. We treat any 404 (real GitHubClientError or any thrown value\n // carrying statusCode 404) as \"no releases\" and fall back to the\n // default branch. Other errors propagate.\n if (is404(error)) {\n resolvedRef = await client.getDefaultBranch(owner, repo);\n } else {\n throw error;\n }\n }\n }\n const resolvedSha = await client.resolveRefToSha(owner, repo, resolvedRef);\n logger.debug(`Resolved ${sourceKey} -> ref=${resolvedRef} sha=${resolvedSha}`);\n return { resolvedRef, resolvedSha, usedTag };\n}\n\n/**\n * List `skills/` and validate which subdirectories are actual skills (contain a\n * SKILL.md). Returns null (with a warn log) when the `skills/` directory 404s so\n * the caller can skip the source. Validation is sequential to avoid hammering\n * the API for large monorepos beyond FETCH_CONCURRENCY_LIMIT.\n */\nasync function discoverValidatedSkills(params: {\n client: GitHubClient;\n semaphore: Semaphore;\n owner: string;\n repo: string;\n resolvedSha: string;\n sourceKey: string;\n logger: Logger;\n}): Promise<Array<{ name: string; path: string }> | null> {\n const { client, semaphore, owner, repo, resolvedSha, sourceKey, logger } = params;\n let topLevel: Awaited<ReturnType<GitHubClient[\"listDirectory\"]>>;\n try {\n topLevel = await client.listDirectory(owner, repo, SKILLS_REMOTE_DIR, resolvedSha);\n } catch (error) {\n if (is404(error)) {\n logger.warn(`No skills/ directory found in ${sourceKey}. Skipping.`);\n return null;\n }\n throw error;\n }\n\n const skillDirs = topLevel\n .filter((e) => e.type === \"dir\")\n .map((e) => ({ name: e.name, path: e.path }));\n\n const validatedSkills: Array<{ name: string; path: string }> = [];\n for (const sk of skillDirs) {\n const info = await withSemaphore(semaphore, () =>\n client.getFileInfo(owner, repo, posix.join(sk.path, SKILL_FILE_NAME), resolvedSha),\n );\n if (info) {\n validatedSkills.push(sk);\n }\n }\n return validatedSkills;\n}\n\n/**\n * Apply the explicit `entry.skills` filter to the validated skills, warning for\n * each requested name that is absent upstream. Returns all validated skills when\n * no filter is provided.\n */\nfunction selectSkills(params: {\n validatedSkills: Array<{ name: string; path: string }>;\n entry: SourceEntry;\n sourceKey: string;\n logger: Logger;\n}): Array<{ name: string; path: string }> {\n const { validatedSkills, entry, sourceKey, logger } = params;\n if (!entry.skills || entry.skills.length === 0) {\n return validatedSkills;\n }\n const requested = new Set(entry.skills);\n const selected = validatedSkills.filter((s) => requested.has(s.name));\n const presentNames = new Set(validatedSkills.map((s) => s.name));\n for (const want of entry.skills) {\n if (!presentNames.has(want)) {\n logger.warn(`Requested skill \"${want}\" not found in ${sourceKey} under skills/. Skipping.`);\n }\n }\n return selected;\n}\n\n/**\n * Frozen-mode per-skill coverage check. Throws when any selected skill has no\n * matching lock installation for the (source, agent, scope) tuple.\n */\nfunction assertFrozenSkillCoverage(params: {\n selected: Array<{ name: string; path: string }>;\n existingLock: GhLock;\n sourceKey: string;\n agent: GhAgent;\n scope: GhScope;\n}): void {\n const { selected, existingLock, sourceKey, agent, scope } = params;\n const missing: string[] = [];\n for (const sk of selected) {\n const locked = findGhLockInstallation(existingLock, {\n source: sourceKey,\n agent,\n scope,\n skill: sk.name,\n });\n if (!locked) {\n missing.push(sk.name);\n }\n }\n if (missing.length > 0) {\n throw new Error(\n `Frozen install failed: rulesync-gh.lock.yaml is missing entries for ${sourceKey} (agent=${agent}, scope=${scope}) skills: ${missing.join(\", \")}. Run 'rulesync install --mode gh' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Fetch, validate, and (under non-frozen) write a single skill's file tree,\n * returning the deployable files. Oversized or out-of-bounds files are skipped\n * with a warn log; SKILL.md files have provenance frontmatter injected.\n */\nasync function buildSkillDeployment(params: {\n sk: { name: string; path: string };\n allFiles: Awaited<ReturnType<typeof listDirectoryRecursive>>;\n client: GitHubClient;\n semaphore: Semaphore;\n owner: string;\n repo: string;\n resolvedSha: string;\n installRelDir: string;\n scopeRoot: string;\n sourceUrl: string;\n repository: string;\n provenanceRef: string;\n sourceKey: string;\n frozen: boolean;\n logger: Logger;\n}): Promise<DeployedFile[]> {\n const {\n sk,\n allFiles,\n client,\n semaphore,\n owner,\n repo,\n resolvedSha,\n installRelDir,\n scopeRoot,\n sourceUrl,\n repository,\n provenanceRef,\n sourceKey,\n frozen,\n logger,\n } = params;\n\n const deployed: DeployedFile[] = [];\n for (const file of allFiles) {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${sourceKey}: ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n // Path of the file relative to the skill directory root upstream.\n const relativeToSkill = posix.relative(sk.path, toPosixPath(file.path));\n if (!relativeToSkill || relativeToSkill.startsWith(\"..\") || posix.isAbsolute(relativeToSkill)) {\n logger.warn(`Skipping \"${file.path}\" from ${sourceKey}: resolved outside of \"${sk.path}\".`);\n continue;\n }\n\n // Path under the scope root (relative). This is the value persisted to\n // the lockfile.\n const deployRelative = toPosixPath(join(installRelDir, sk.name, relativeToSkill));\n // Path-traversal hardening rooted at the scope root, then a tighter\n // check rooted at the per-(agent,scope) install dir to refuse anything\n // that escapes the agent-specific deployment directory.\n checkPathTraversal({ relativePath: deployRelative, intendedRootDir: scopeRoot });\n const installAbs = join(scopeRoot, installRelDir);\n const withinInstallDir = toPosixPath(join(sk.name, relativeToSkill));\n checkPathTraversal({ relativePath: withinInstallDir, intendedRootDir: installAbs });\n\n let content = await withSemaphore(semaphore, () =>\n client.getFileContent(owner, repo, file.path, resolvedSha),\n );\n const byteLength = Buffer.byteLength(content, \"utf8\");\n if (byteLength > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping \"${file.path}\" from ${sourceKey}: fetched ${(byteLength / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,\n );\n continue;\n }\n\n // Inject provenance frontmatter into SKILL.md files. Other files\n // (e.g. supporting markdown, scripts) pass through unchanged.\n if (basename(file.path) === SKILL_FILE_NAME) {\n try {\n content = injectSourceMetadata({\n content,\n source: sourceUrl,\n repository,\n ref: provenanceRef,\n });\n } catch {\n // Frontmatter exists but is not parseable. Fall back to a fresh\n // prepend so we still record provenance — but warn the user.\n logger.warn(\n `Frontmatter in ${file.path} (${sourceKey}) is invalid. Prepending a fresh provenance block.`,\n );\n content = `---\\nsource: ${sourceUrl}\\nrepository: ${repository}\\nref: ${provenanceRef}\\n---\\n${content}`;\n }\n }\n\n const absolutePath = join(scopeRoot, deployRelative);\n deployed.push({ relativeToScopeRoot: deployRelative, absolutePath, content });\n\n if (!frozen) {\n await writeFileContent(absolutePath, content);\n }\n }\n return deployed;\n}\n\n/**\n * Frozen integrity check: refuse to overwrite known-good bytes with tampered\n * ones when the prior content_hash matches the rulesync format. Hashes not\n * written by rulesync are skipped (debug-logged), preserving the commit-SHA pin.\n */\nfunction assertFrozenSkillIntegrity(params: {\n frozen: boolean;\n locked: GhLockInstallation | undefined;\n contentHash: string;\n sourceKey: string;\n skillName: string;\n agent: GhAgent;\n scope: GhScope;\n logger: Logger;\n}): void {\n const { frozen, locked, contentHash, sourceKey, skillName, agent, scope, logger } = params;\n if (frozen && locked?.content_hash) {\n if (RULESYNC_CONTENT_HASH_REGEX.test(locked.content_hash)) {\n if (locked.content_hash !== contentHash) {\n throw new Error(\n `content_hash mismatch for ${sourceKey} skill \"${skillName}\" (agent=${agent}, scope=${scope}): lock=${locked.content_hash} computed=${contentHash}. Refuse to trust the deployment under --frozen.`,\n );\n }\n } else {\n logger.debug(\n `Skipping content_hash integrity check for ${sourceKey} skill \"${skillName}\": recorded hash \"${locked.content_hash}\" was not written by rulesync.`,\n );\n }\n }\n}\n\nasync function removeStaleFile(params: {\n relativePath: string;\n scope: GhScope;\n projectRoot: string;\n logger: Logger;\n}): Promise<void> {\n const { relativePath, scope, projectRoot, logger } = params;\n if (posix.isAbsolute(relativePath) || relativePath.split(/[/\\\\]/).includes(\"..\")) {\n logger.warn(`Refusing to remove stale gh file with suspicious path: \"${relativePath}\".`);\n return;\n }\n const scopeRoot = scope === \"user\" ? getHomeDirectory() : projectRoot;\n try {\n checkPathTraversal({ relativePath, intendedRootDir: scopeRoot });\n } catch {\n logger.warn(`Refusing to remove stale gh file outside ${scope} root: \"${relativePath}\".`);\n return;\n }\n const absolute = join(scopeRoot, relativePath);\n await removeFile(absolute);\n logger.debug(`Removed stale gh file: ${relativePath}`);\n}\n\n/**\n * Detect a 404-like error in a way that tolerates both real `GitHubClientError`\n * instances and any other thrown value that exposes a numeric `statusCode`\n * (e.g. plain Errors raised from a test mock that does not import the real\n * client class).\n */\nfunction is404(error: unknown): boolean {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return true;\n }\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"statusCode\" in error &&\n error.statusCode === 404\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * SHA-256 over a canonical, order-independent representation of the deployed\n * files. Identical algorithm to the apm-install hash so users familiar with\n * one mode can read the other.\n */\nfunction computeContentHash(\n files: Array<{ relativeToScopeRoot: string; content: string }>,\n): string {\n const hash = createHash(\"sha256\");\n for (const { relativeToScopeRoot, content } of files) {\n hash.update(relativeToScopeRoot);\n hash.update(\"\\0\");\n hash.update(content);\n hash.update(\"\\0\");\n }\n return `sha256:${hash.digest(\"hex\")}`;\n}\n","import { execFile } from \"node:child_process\";\nimport { isAbsolute, join, posix, relative } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport { MAX_FILE_SIZE } from \"../constants/rulesync-paths.js\";\nimport {\n createTempDirectory,\n directoryExists,\n getFileSize,\n isSymlink,\n listDirectoryFiles,\n readFileContent,\n removeTempDirectory,\n} from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { findControlCharacter } from \"../utils/validation.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Timeout for all git CLI operations (60 seconds). */\nconst GIT_TIMEOUT_MS = 60_000;\n\nconst ALLOWED_URL_SCHEMES =\n /^(https?:\\/\\/|ssh:\\/\\/|git:\\/\\/|file:\\/\\/\\/).+$|^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9.-]+:[a-zA-Z0-9_.+/~-]+$/;\n\nconst INSECURE_URL_SCHEMES = /^(git:\\/\\/|http:\\/\\/)/;\n\nexport class GitClientError extends Error {\n constructor(message: string, cause?: unknown) {\n super(message, { cause });\n this.name = \"GitClientError\";\n }\n}\n\nexport function validateGitUrl(url: string, options?: { logger?: Logger }): void {\n const ctrl = findControlCharacter(url);\n if (ctrl) {\n throw new GitClientError(\n `Git URL contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n if (!ALLOWED_URL_SCHEMES.test(url)) {\n throw new GitClientError(\n `Unsupported or unsafe git URL: \"${url}\". Use https, ssh, git, or file schemes.`,\n );\n }\n if (INSECURE_URL_SCHEMES.test(url)) {\n options?.logger?.warn(\n `URL \"${url}\" uses an unencrypted protocol. Consider using https:// or ssh:// instead.`,\n );\n }\n}\n\n/**\n * Validate a ref string before passing to git commands.\n * Rejects refs that start with \"-\" or contain control characters.\n */\nexport function validateRef(ref: string): void {\n if (ref.startsWith(\"-\")) {\n throw new GitClientError(`Ref must not start with \"-\": \"${ref}\"`);\n }\n const ctrl = findControlCharacter(ref);\n if (ctrl) {\n throw new GitClientError(\n `Ref contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n}\n\nlet gitChecked = false;\n\nexport async function checkGitAvailable(): Promise<void> {\n if (gitChecked) return;\n try {\n await execFileAsync(\"git\", [\"--version\"], { timeout: GIT_TIMEOUT_MS });\n gitChecked = true;\n } catch {\n throw new GitClientError(\"git is not installed or not found in PATH\");\n }\n}\n\n/** Reset the cached git availability check (for testing). */\nexport function resetGitCheck(): void {\n gitChecked = false;\n}\n\nexport async function resolveDefaultRef(url: string): Promise<{ ref: string; sha: string }> {\n validateGitUrl(url);\n await checkGitAvailable();\n try {\n const { stdout } = await execFileAsync(\"git\", [\"ls-remote\", \"--symref\", \"--\", url, \"HEAD\"], {\n timeout: GIT_TIMEOUT_MS,\n });\n const ref = stdout.match(/^ref: refs\\/heads\\/(.+)\\tHEAD$/m)?.[1];\n const sha = stdout.match(/^([0-9a-f]{40})\\tHEAD$/m)?.[1];\n if (!ref || !sha) throw new GitClientError(`Could not parse default branch from: ${url}`);\n validateRef(ref);\n return { ref, sha };\n } catch (error) {\n if (error instanceof GitClientError) throw error;\n throw new GitClientError(`Failed to resolve default ref for ${url}`, error);\n }\n}\n\nexport async function resolveRefToSha(url: string, ref: string): Promise<string> {\n validateGitUrl(url);\n validateRef(ref);\n await checkGitAvailable();\n try {\n const { stdout } = await execFileAsync(\"git\", [\"ls-remote\", \"--\", url, ref], {\n timeout: GIT_TIMEOUT_MS,\n });\n const sha = stdout.match(/^([0-9a-f]{40})\\t/m)?.[1];\n if (!sha) throw new GitClientError(`Ref \"${ref}\" not found in ${url}`);\n return sha;\n } catch (error) {\n if (error instanceof GitClientError) throw error;\n throw new GitClientError(`Failed to resolve ref \"${ref}\" for ${url}`, error);\n }\n}\n\n/**\n * Clone a repo at the given ref and return all files under skillsPath.\n * The `ref` must be a branch or tag name (not a commit SHA) because\n * `git clone --branch` does not accept raw SHAs.\n */\nexport async function fetchSkillFiles(params: {\n url: string;\n ref: string;\n skillsPath: string;\n logger?: Logger;\n}): Promise<Array<{ relativePath: string; content: string; size: number }>> {\n const { url, ref, skillsPath, logger } = params;\n validateGitUrl(url, { logger });\n validateRef(ref);\n if (skillsPath.split(/[/\\\\]/).includes(\"..\") || isAbsolute(skillsPath)) {\n throw new GitClientError(\n `Invalid skillsPath \"${skillsPath}\": must be a relative path without \"..\"`,\n );\n }\n const ctrl = findControlCharacter(skillsPath);\n if (ctrl) {\n throw new GitClientError(\n `skillsPath contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n await checkGitAvailable();\n const tmpDir = await createTempDirectory(\"rulesync-git-\");\n // Treat empty/\".\" paths as the repository root. Cone-mode sparse-checkout\n // with such patterns only restores the top-level files (it intentionally\n // excludes any subdirectory), so we must check out the entire working tree\n // instead. Otherwise repositories whose skills live directly at the root\n // (e.g. `<repo>/<skill-name>/SKILL.md` without a `skills/` container)\n // would only yield root-level files like README.md.\n // Normalize first so variants like \"./.\", \".//\", or Windows \".\\\\\" are also\n // recognized as the root and don't fall back to the (buggy) sparse-checkout path.\n const normalizedSkillsPath = posix.normalize(skillsPath.replace(/\\\\/g, \"/\")).replace(/\\/+$/, \"\");\n const isRootPath = normalizedSkillsPath === \"\" || normalizedSkillsPath === \".\";\n try {\n await execFileAsync(\n \"git\",\n [\n \"clone\",\n \"--depth\",\n \"1\",\n \"--branch\",\n ref,\n \"--no-checkout\",\n \"--filter=blob:none\",\n \"--\",\n url,\n tmpDir,\n ],\n { timeout: GIT_TIMEOUT_MS },\n );\n if (isRootPath) {\n // Disable sparse-checkout and restore the full tree.\n await execFileAsync(\"git\", [\"-C\", tmpDir, \"sparse-checkout\", \"disable\"], {\n timeout: GIT_TIMEOUT_MS,\n });\n } else {\n await execFileAsync(\"git\", [\"-C\", tmpDir, \"sparse-checkout\", \"set\", \"--\", skillsPath], {\n timeout: GIT_TIMEOUT_MS,\n });\n }\n await execFileAsync(\"git\", [\"-C\", tmpDir, \"checkout\"], { timeout: GIT_TIMEOUT_MS });\n const skillsDir = isRootPath ? tmpDir : join(tmpDir, skillsPath);\n if (!(await directoryExists(skillsDir))) return [];\n return await walkDirectory(skillsDir, skillsDir, 0, { totalFiles: 0, totalSize: 0 }, logger);\n } catch (error) {\n if (error instanceof GitClientError) throw error;\n throw new GitClientError(`Failed to fetch skill files from ${url}`, error);\n } finally {\n await removeTempDirectory(tmpDir);\n }\n}\n\nconst MAX_WALK_DEPTH = 20;\nconst MAX_TOTAL_FILES = 10_000;\nconst MAX_TOTAL_SIZE = 100 * 1024 * 1024; // 100 MB\n\n/** Mutable context for tracking totals across recursive walkDirectory calls. */\ntype WalkContext = { totalFiles: number; totalSize: number };\n\nasync function walkDirectory(\n dir: string,\n outputRoot: string,\n depth: number = 0,\n ctx: WalkContext = { totalFiles: 0, totalSize: 0 },\n logger?: Logger,\n): Promise<Array<{ relativePath: string; content: string; size: number }>> {\n if (depth > MAX_WALK_DEPTH) {\n throw new GitClientError(\n `Directory tree exceeds max depth of ${MAX_WALK_DEPTH}: \"${dir}\". Aborting to prevent resource exhaustion.`,\n );\n }\n const results: Array<{ relativePath: string; content: string; size: number }> = [];\n for (const name of await listDirectoryFiles(dir)) {\n if (name === \".git\") continue;\n const fullPath = join(dir, name);\n if (await isSymlink(fullPath)) {\n logger?.warn(`Skipping symlink \"${fullPath}\".`);\n continue;\n }\n if (await directoryExists(fullPath)) {\n results.push(...(await walkDirectory(fullPath, outputRoot, depth + 1, ctx, logger)));\n } else {\n const size = await getFileSize(fullPath);\n if (size > MAX_FILE_SIZE) {\n logger?.warn(\n `Skipping file \"${fullPath}\" (${(size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n continue;\n }\n ctx.totalFiles++;\n ctx.totalSize += size;\n if (ctx.totalFiles >= MAX_TOTAL_FILES) {\n throw new GitClientError(\n `Repository exceeds max file count of ${MAX_TOTAL_FILES}. Aborting to prevent resource exhaustion.`,\n );\n }\n if (ctx.totalSize >= MAX_TOTAL_SIZE) {\n throw new GitClientError(\n `Repository exceeds max total size of ${MAX_TOTAL_SIZE / 1024 / 1024}MB. Aborting to prevent resource exhaustion.`,\n );\n }\n const content = await readFileContent(fullPath);\n results.push({ relativePath: relative(outputRoot, fullPath), content, size });\n }\n }\n return results;\n}\n","import { createHash } from \"node:crypto\";\n\nimport type { Logger } from \"../utils/logger.js\";\nimport { findControlCharacter } from \"../utils/validation.js\";\n\n/**\n * Minimal npm-compatible registry client for the EXPERIMENTAL `npm` transport.\n * Works against any registry implementing the npm registry API (npmjs.org,\n * JFrog Artifactory, Sonatype Nexus, Verdaccio, ...). Intentionally avoids\n * `.npmrc` parsing: authentication uses a bearer token from an environment\n * variable (`NPM_TOKEN` by default, or a per-source `tokenEnv`).\n */\n\nexport const DEFAULT_NPM_REGISTRY_URL = \"https://registry.npmjs.org\";\nexport const DEFAULT_NPM_TOKEN_ENV = \"NPM_TOKEN\";\n\n/** Abbreviated packument media type (install metadata only). */\nconst PACKUMENT_ACCEPT_HEADER = \"application/vnd.npm.install-v1+json\";\n\n/** Timeout for registry HTTP requests (60 seconds). */\nconst NPM_FETCH_TIMEOUT_MS = 60_000;\n\n/** Maximum accepted tarball size (compressed), aligned with the extraction cap. */\nconst MAX_TARBALL_SIZE = 100 * 1024 * 1024;\n\n/**\n * npm package name rules (scoped or unscoped, URL-safe characters only).\n * This also guards against URL path injection into registry requests.\n */\nconst NPM_PACKAGE_NAME_REGEX = /^(@[a-z0-9][a-z0-9._~-]*\\/)?[a-z0-9][a-z0-9._~-]*$/i;\nconst MAX_NPM_PACKAGE_NAME_LENGTH = 214;\n\nconst INTEGRITY_ALGORITHM_PREFERENCE = [\"sha512\", \"sha384\", \"sha256\", \"sha1\"] as const;\ntype IntegrityAlgorithm = (typeof INTEGRITY_ALGORITHM_PREFERENCE)[number];\n\nexport class NpmClientError extends Error {\n public readonly statusCode?: number;\n\n constructor(message: string, options?: { statusCode?: number; cause?: unknown }) {\n super(message, { cause: options?.cause });\n this.name = \"NpmClientError\";\n this.statusCode = options?.statusCode;\n }\n}\n\nexport type NpmDist = {\n tarball: string;\n integrity?: string;\n shasum?: string;\n};\n\nexport type NpmPackument = {\n name?: string;\n \"dist-tags\"?: Record<string, string>;\n versions?: Record<string, { dist?: NpmDist }>;\n};\n\nexport function validateNpmPackageName(name: string): void {\n if (name.length > MAX_NPM_PACKAGE_NAME_LENGTH || !NPM_PACKAGE_NAME_REGEX.test(name)) {\n throw new NpmClientError(\n `Invalid npm package name: \"${name}\". Expected \"name\" or \"@scope/name\".`,\n );\n }\n}\n\nexport function validateNpmRegistryUrl(url: string, options?: { logger?: Logger }): void {\n const ctrl = findControlCharacter(url);\n if (ctrl) {\n throw new NpmClientError(\n `Registry URL contains control character ${ctrl.hex} at position ${ctrl.position}`,\n );\n }\n if (!url.startsWith(\"https://\") && !url.startsWith(\"http://\")) {\n throw new NpmClientError(`Unsupported registry URL: \"${url}\". Use https:// (or http://).`);\n }\n if (url.startsWith(\"http://\")) {\n options?.logger?.warn(\n `Registry URL \"${url}\" uses an unencrypted protocol. Consider using https:// instead.`,\n );\n }\n}\n\n/**\n * Resolve the registry token from the environment. When `tokenEnv` is set it\n * must name an existing environment variable; otherwise `NPM_TOKEN` is used\n * when present. The token value itself is never logged.\n */\nexport function resolveNpmToken(params: { tokenEnv?: string }): string | undefined {\n const { tokenEnv } = params;\n if (tokenEnv !== undefined) {\n const value = process.env[tokenEnv];\n if (value === undefined || value === \"\") {\n throw new NpmClientError(\n `Environment variable \"${tokenEnv}\" (from tokenEnv) is not set. Export it or remove the tokenEnv field.`,\n );\n }\n return value;\n }\n const fallback = process.env[DEFAULT_NPM_TOKEN_ENV];\n return fallback === undefined || fallback === \"\" ? undefined : fallback;\n}\n\n/** Build the packument URL for a (possibly scoped) package on a registry. */\nexport function buildPackumentUrl(params: { registryUrl: string; packageName: string }): string {\n const { registryUrl, packageName } = params;\n // Validate here too so the URL can never carry extra path segments, even if a\n // caller skips the fetch-level validation.\n validateNpmPackageName(packageName);\n const base = registryUrl.endsWith(\"/\") ? registryUrl : `${registryUrl}/`;\n // Scoped package names keep the \"@\" but encode the slash, per the npm registry API.\n const encodedName = packageName.replaceAll(\"/\", \"%2F\");\n return new URL(encodedName, base).toString();\n}\n\nasync function fetchWithTimeout(url: string, headers: Record<string, string>): Promise<Response> {\n try {\n return await fetch(url, {\n headers,\n redirect: \"follow\",\n signal: AbortSignal.timeout(NPM_FETCH_TIMEOUT_MS),\n });\n } catch (error) {\n throw new NpmClientError(`Network error while requesting ${url}`, { cause: error });\n }\n}\n\n/**\n * Fetch the (abbreviated) packument for a package from a registry.\n */\nexport async function fetchPackument(params: {\n registryUrl: string;\n packageName: string;\n token?: string;\n}): Promise<NpmPackument> {\n const { registryUrl, packageName, token } = params;\n validateNpmPackageName(packageName);\n const url = buildPackumentUrl({ registryUrl, packageName });\n\n const headers: Record<string, string> = { Accept: PACKUMENT_ACCEPT_HEADER };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n const response = await fetchWithTimeout(url, headers);\n if (!response.ok) {\n throw new NpmClientError(\n `Failed to fetch package metadata for \"${packageName}\" from ${registryUrl}: HTTP ${response.status}`,\n { statusCode: response.status },\n );\n }\n try {\n return (await response.json()) as NpmPackument;\n } catch (error) {\n throw new NpmClientError(\n `Failed to parse package metadata for \"${packageName}\" from ${registryUrl}`,\n { cause: error },\n );\n }\n}\n\n/**\n * Resolve a requested version or dist-tag against a packument. Only exact\n * versions and dist-tags are supported — semver ranges are intentionally out\n * of scope (no semver dependency).\n */\nexport function resolvePackumentVersion(params: {\n packument: NpmPackument;\n packageName: string;\n requested: string;\n}): string {\n const { packument, packageName, requested } = params;\n const versions = packument.versions ?? {};\n if (Object.prototype.hasOwnProperty.call(versions, requested)) {\n return requested;\n }\n const distTags = packument[\"dist-tags\"] ?? {};\n const tagged = Object.prototype.hasOwnProperty.call(distTags, requested)\n ? distTags[requested]\n : undefined;\n if (tagged !== undefined && Object.prototype.hasOwnProperty.call(versions, tagged)) {\n return tagged;\n }\n throw new NpmClientError(\n `Could not resolve \"${packageName}@${requested}\": not an exact published version or dist-tag. Note: semver ranges are not supported by the npm transport.`,\n );\n}\n\n/** Get the dist metadata (tarball URL, integrity) for a resolved version. */\nexport function getPackumentVersionDist(params: {\n packument: NpmPackument;\n packageName: string;\n version: string;\n}): NpmDist {\n const { packument, packageName, version } = params;\n const versions = packument.versions ?? {};\n const entry = Object.prototype.hasOwnProperty.call(versions, version)\n ? versions[version]\n : undefined;\n const dist = entry?.dist;\n if (!dist?.tarball) {\n throw new NpmClientError(\n `Registry metadata for \"${packageName}@${version}\" is missing the dist.tarball URL.`,\n );\n }\n return dist;\n}\n\n/**\n * Download a package tarball. The Authorization header is only attached when\n * the tarball is hosted on the same origin (scheme + host) as the registry,\n * so the token never leaks to third-party CDNs or plaintext downgrades.\n */\nexport async function fetchTarball(params: {\n tarballUrl: string;\n registryUrl: string;\n token?: string;\n /** Maximum accepted tarball size in bytes. Overridable for tests only. */\n maxSize?: number;\n}): Promise<Buffer> {\n const { tarballUrl, registryUrl, token } = params;\n const maxSize = params.maxSize ?? MAX_TARBALL_SIZE;\n if (!tarballUrl.startsWith(\"https://\") && !tarballUrl.startsWith(\"http://\")) {\n throw new NpmClientError(\n `Unsupported tarball URL: \"${tarballUrl}\". Use https:// (or http://).`,\n );\n }\n\n const headers: Record<string, string> = {};\n if (token && isSameOrigin(tarballUrl, registryUrl)) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n const response = await fetchWithTimeout(tarballUrl, headers);\n if (!response.ok) {\n throw new NpmClientError(`Failed to download tarball ${tarballUrl}: HTTP ${response.status}`, {\n statusCode: response.status,\n });\n }\n const contentLength = Number.parseInt(response.headers.get(\"content-length\") ?? \"\", 10);\n if (Number.isFinite(contentLength) && contentLength > maxSize) {\n throw new NpmClientError(oversizedTarballMessage(tarballUrl, maxSize));\n }\n return await readBodyWithLimit({ response, tarballUrl, maxSize });\n}\n\nfunction oversizedTarballMessage(tarballUrl: string, maxSize: number): string {\n return `Tarball ${tarballUrl} exceeds max size of ${maxSize / 1024 / 1024}MB.`;\n}\n\n/**\n * Read a response body incrementally, aborting as soon as the size cap is\n * exceeded. content-length can be absent or forged, so the streaming check is\n * the actual enforcement of the cap.\n */\nasync function readBodyWithLimit(params: {\n response: Response;\n tarballUrl: string;\n maxSize: number;\n}): Promise<Buffer> {\n const { response, tarballUrl, maxSize } = params;\n const reader = response.body?.getReader();\n if (!reader) {\n // Responses without a body stream (e.g. some test doubles): buffer\n // with a post-hoc check.\n const arrayBuffer = await response.arrayBuffer();\n if (arrayBuffer.byteLength > maxSize) {\n throw new NpmClientError(oversizedTarballMessage(tarballUrl, maxSize));\n }\n return Buffer.from(arrayBuffer);\n }\n\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n totalBytes += value.byteLength;\n if (totalBytes > maxSize) {\n await reader.cancel();\n throw new NpmClientError(oversizedTarballMessage(tarballUrl, maxSize));\n }\n chunks.push(Buffer.from(value));\n }\n return Buffer.concat(chunks);\n}\n\nfunction isSameOrigin(urlA: string, urlB: string): boolean {\n try {\n return new URL(urlA).origin === new URL(urlB).origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Convert a hex sha1 shasum to the SRI form used by `verifyTarballIntegrity`.\n * Rejects malformed shasum values so a broken value is never recorded in the\n * lockfile as a seemingly valid SRI string.\n */\nexport function shasumToSri(shasum: string): string {\n if (!/^[0-9a-f]{40}$/i.test(shasum)) {\n throw new NpmClientError(`Malformed sha1 shasum in registry metadata: \"${shasum}\"`);\n }\n return `sha1-${Buffer.from(shasum, \"hex\").toString(\"base64\")}`;\n}\n\n/**\n * Verify a downloaded tarball against registry integrity metadata.\n * Prefers the strongest supported algorithm in the SRI `integrity` string and\n * falls back to the legacy sha1 `shasum`. An `integrity` string that is\n * present but cannot be parsed fails closed; a warning is only logged when\n * the registry provides no integrity metadata at all.\n */\nexport function verifyTarballIntegrity(params: {\n tarball: Buffer;\n integrity?: string;\n shasum?: string;\n context: string;\n logger?: Logger;\n}): void {\n const { tarball, integrity, shasum, context, logger } = params;\n\n if (integrity !== undefined) {\n const sri = pickStrongestSriEntry(integrity);\n if (!sri) {\n // Fail closed: a present-but-unparseable integrity value must never\n // silently disable verification (e.g. a corrupted lockfile entry).\n throw new NpmClientError(\n `Unsupported or malformed integrity metadata for ${context}. Expected an SRI string with sha512/sha384/sha256/sha1.`,\n );\n }\n const actual = createHash(sri.algorithm).update(tarball).digest(\"base64\");\n if (actual !== sri.digest) {\n throw new NpmClientError(\n `Integrity verification failed for ${context}: expected ${sri.algorithm}-${sri.digest}, got ${sri.algorithm}-${actual}. The tarball may have been tampered with.`,\n );\n }\n return;\n }\n\n if (shasum) {\n const actual = createHash(\"sha1\").update(tarball).digest(\"hex\");\n if (actual !== shasum.toLowerCase()) {\n throw new NpmClientError(\n `Integrity verification failed for ${context}: expected sha1 ${shasum}, got ${actual}. The tarball may have been tampered with.`,\n );\n }\n return;\n }\n\n logger?.warn(`No integrity metadata available for ${context}; skipping tarball verification.`);\n}\n\nfunction pickStrongestSriEntry(\n integrity: string | undefined,\n): { algorithm: IntegrityAlgorithm; digest: string } | undefined {\n if (!integrity) {\n return undefined;\n }\n const entries = integrity\n .split(/\\s+/)\n .map((entry) => {\n const separatorIndex = entry.indexOf(\"-\");\n if (separatorIndex === -1) return undefined;\n const algorithm = entry.slice(0, separatorIndex);\n // Strip SRI options (`sha512-<digest>?opt`) from the digest.\n const digest = entry.slice(separatorIndex + 1).split(\"?\")[0] ?? \"\";\n const known = INTEGRITY_ALGORITHM_PREFERENCE.find((a) => a === algorithm);\n if (!known || digest.length === 0) return undefined;\n return { algorithm: known, digest };\n })\n .filter((entry): entry is { algorithm: IntegrityAlgorithm; digest: string } => Boolean(entry));\n\n for (const algorithm of INTEGRITY_ALGORITHM_PREFERENCE) {\n const match = entries.find((entry) => entry.algorithm === algorithm);\n if (match) {\n return match;\n }\n }\n return undefined;\n}\n\n/**\n * Log contextual hints for NpmClientError to help users troubleshoot\n * authentication problems without ever logging the token itself.\n */\nexport function logNpmAuthHints(params: { error: NpmClientError; logger: Logger }): void {\n const { error, logger } = params;\n if (error.statusCode === 401 || error.statusCode === 403) {\n logger.info(\n \"Hint: The registry rejected the request. Set NPM_TOKEN (or the per-source tokenEnv variable) to a token with read access. Note: .npmrc files are not read by the npm transport.\",\n );\n } else if (error.statusCode === 404) {\n logger.info(\n \"Hint: Package not found. Check the package name and the registry URL. Some registries also return 404 for unauthorized requests.\",\n );\n }\n}\n","import { join } from \"node:path\";\n\nimport { optional, z } from \"zod/mini\";\n\nimport { RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { fileExists, readFileContent, writeFileContent } from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/**\n * Lockfile for npm-transport sources (EXPERIMENTAL), written to\n * `rulesync-npm.lock.json` at the project root. Kept separate from the main\n * `rulesync.lock` because that lockfile pins git commit SHAs, while npm\n * sources pin a resolved package version plus the registry tarball integrity.\n * Mirrors the conventions of the gh (`rulesync-gh.lock.yaml`) and apm\n * (`rulesync-apm.lock.yaml`) lockfiles, which are also mode/transport-specific.\n */\n\n/** Current npm lockfile format version. Bump when the schema changes. */\nexport const NPM_LOCKFILE_VERSION = 1;\n\nconst NpmLockedSkillSchema = z.object({\n integrity: z.string(),\n});\n\n/**\n * Schema for a single locked npm source entry.\n */\nconst NpmLockedSourceSchema = z.object({\n registry: optional(z.string()),\n requestedVersion: optional(z.string()),\n resolvedVersion: z.string(),\n /** SRI integrity of the package tarball as reported by the registry. */\n integrity: optional(z.string()),\n resolvedAt: optional(z.string()),\n skills: z.record(z.string(), NpmLockedSkillSchema),\n});\nexport type NpmLockedSource = z.infer<typeof NpmLockedSourceSchema>;\n\nconst NpmSourcesLockSchema = z.object({\n lockfileVersion: z.number(),\n sources: z.record(z.string(), NpmLockedSourceSchema),\n});\nexport type NpmSourcesLock = z.infer<typeof NpmSourcesLockSchema>;\n\n/**\n * Create an empty npm lockfile structure.\n */\nexport function createEmptyNpmLock(): NpmSourcesLock {\n return { lockfileVersion: NPM_LOCKFILE_VERSION, sources: {} };\n}\n\n/**\n * Read the npm lockfile from disk.\n * @returns The parsed lockfile, or an empty lockfile if it doesn't exist or is invalid.\n */\nexport async function readNpmLockFile(params: {\n projectRoot: string;\n logger: Logger;\n}): Promise<NpmSourcesLock> {\n const { logger } = params;\n const lockPath = join(params.projectRoot, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH);\n\n if (!(await fileExists(lockPath))) {\n logger.debug(\"No npm sources lockfile found, starting fresh.\");\n return createEmptyNpmLock();\n }\n\n try {\n const content = await readFileContent(lockPath);\n const result = NpmSourcesLockSchema.safeParse(JSON.parse(content));\n if (result.success) {\n return result.data;\n }\n logger.warn(\n `Invalid npm sources lockfile format (${RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`,\n );\n return createEmptyNpmLock();\n } catch {\n logger.warn(\n `Failed to read npm sources lockfile (${RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`,\n );\n return createEmptyNpmLock();\n }\n}\n\n/**\n * Write the npm lockfile to disk.\n */\nexport async function writeNpmLockFile(params: {\n projectRoot: string;\n lock: NpmSourcesLock;\n logger: Logger;\n}): Promise<void> {\n const { logger } = params;\n const lockPath = join(params.projectRoot, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH);\n const content = JSON.stringify(params.lock, null, 2) + \"\\n\";\n await writeFileContent(lockPath, content);\n logger.debug(`Wrote npm sources lockfile to ${lockPath}`);\n}\n\n/**\n * Normalize an npm source key (package name) for lockfile lookups.\n */\nexport function normalizeNpmSourceKey(source: string): string {\n return source.trim();\n}\n\n/**\n * Get the locked entry for an npm source key, if it exists.\n */\nexport function getNpmLockedSource(\n lock: NpmSourcesLock,\n sourceKey: string,\n): NpmLockedSource | undefined {\n const normalized = normalizeNpmSourceKey(sourceKey);\n return Object.prototype.hasOwnProperty.call(lock.sources, normalized)\n ? lock.sources[normalized]\n : undefined;\n}\n\n/**\n * Set (or update) a locked entry for an npm source key (immutable).\n */\nexport function setNpmLockedSource(\n lock: NpmSourcesLock,\n sourceKey: string,\n entry: NpmLockedSource,\n): NpmSourcesLock {\n return {\n lockfileVersion: lock.lockfileVersion,\n sources: {\n ...lock.sources,\n [normalizeNpmSourceKey(sourceKey)]: entry,\n },\n };\n}\n\n/**\n * Get the skill names from a locked npm source entry.\n */\nexport function getNpmLockedSkillNames(entry: NpmLockedSource): string[] {\n return Object.keys(entry.skills);\n}\n","import { gunzipSync } from \"node:zlib\";\n\n/**\n * Minimal, hardened tar reader for npm package tarballs (EXPERIMENTAL npm\n * transport). Intentionally supports only the subset of the (pax-extended)\n * ustar format that npm-compatible registries produce:\n *\n * - regular files (typeflag \"0\" / \"\\0\")\n * - directories (typeflag \"5\") — skipped; directories are created implicitly\n * - pax extended headers (typeflag \"x\") — only the `path` override is honored\n * - GNU long names (typeflag \"L\")\n *\n * Everything else (symlinks, hardlinks, devices, FIFOs, ...) is skipped and\n * never materialized. Extraction is bounded by file-count and total-byte caps\n * to prevent decompression bombs, and every entry path is validated against\n * traversal (absolute paths, `..` segments, backslashes).\n */\n\nconst BLOCK_SIZE = 512;\n\n/** Maximum number of files extracted from a single package tarball. */\nexport const MAX_TAR_FILES = 10_000;\n/** Maximum total extracted bytes from a single package tarball (100 MB). */\nexport const MAX_TAR_TOTAL_BYTES = 100 * 1024 * 1024;\n\nexport class NpmTarError extends Error {\n constructor(message: string, cause?: unknown) {\n super(message, { cause });\n this.name = \"NpmTarError\";\n }\n}\n\nexport type TarFileEntry = {\n /**\n * Entry path relative to the package root. The first path component of every\n * entry (conventionally `package/` in npm tarballs, but registries may use a\n * different folder name) is stripped, matching `tar --strip-components=1`.\n */\n relativePath: string;\n content: Buffer;\n};\n\n/**\n * Gunzip and extract a npm package tarball into an in-memory file list.\n * Throws {@link NpmTarError} on malformed archives, traversal attempts, or\n * resource-limit violations.\n */\nexport function extractPackageTarball(params: {\n tarball: Buffer;\n maxFiles?: number;\n maxTotalBytes?: number;\n onSkippedEntry?: (message: string) => void;\n}): TarFileEntry[] {\n const { tarball, onSkippedEntry } = params;\n const maxFiles = params.maxFiles ?? MAX_TAR_FILES;\n const maxTotalBytes = params.maxTotalBytes ?? MAX_TAR_TOTAL_BYTES;\n\n let tar: Buffer;\n try {\n // Cap the decompressed size at the gzip layer as well: the total-byte cap\n // plus generous headroom for tar headers/padding (3 blocks per file).\n tar = gunzipSync(tarball, {\n maxOutputLength: maxTotalBytes + maxFiles * 3 * BLOCK_SIZE + 2 * BLOCK_SIZE,\n });\n } catch (error) {\n throw new NpmTarError(\"Failed to gunzip package tarball\", error);\n }\n\n return parseTarBuffer({ tar, maxFiles, maxTotalBytes, onSkippedEntry });\n}\n\nfunction parseTarBuffer(params: {\n tar: Buffer;\n maxFiles: number;\n maxTotalBytes: number;\n onSkippedEntry?: (message: string) => void;\n}): TarFileEntry[] {\n const { tar, maxFiles, maxTotalBytes, onSkippedEntry } = params;\n const files: TarFileEntry[] = [];\n let totalBytes = 0;\n let offset = 0;\n let pendingLongName: string | undefined;\n let pendingPaxPath: string | undefined;\n\n while (offset + BLOCK_SIZE <= tar.length) {\n const header = tar.subarray(offset, offset + BLOCK_SIZE);\n if (isZeroBlock(header)) {\n break;\n }\n verifyHeaderChecksum(header);\n\n const size = parseOctalField(header, 124, 12, \"size\");\n const typeflag = String.fromCharCode(header[156] ?? 0);\n const dataStart = offset + BLOCK_SIZE;\n const dataEnd = dataStart + size;\n if (dataEnd > tar.length) {\n throw new NpmTarError(\"Truncated tar archive: entry data extends past end of archive\");\n }\n\n switch (typeflag) {\n case \"x\": {\n const records = parsePaxRecords(tar.subarray(dataStart, dataEnd));\n if (records.has(\"size\")) {\n // A pax size override means the octal size field is unreliable; a\n // minimal reader cannot stay aligned, so refuse instead of misparsing.\n throw new NpmTarError(\"Unsupported tar archive: pax size override is not supported\");\n }\n pendingPaxPath = records.get(\"path\") ?? pendingPaxPath;\n break;\n }\n case \"L\": {\n pendingLongName = trimAtFirstNul(tar.toString(\"utf8\", dataStart, dataEnd));\n break;\n }\n case \"g\": {\n // Global pax header. Harmless records are ignored, but size/path\n // overrides would make this reader disagree with full tar\n // implementations (parser-differential risk), so refuse them.\n const records = parsePaxRecords(tar.subarray(dataStart, dataEnd));\n if (records.has(\"size\") || records.has(\"path\")) {\n throw new NpmTarError(\n \"Unsupported tar archive: global pax size/path overrides are not supported\",\n );\n }\n break;\n }\n case \"0\":\n case \"\\0\": {\n const rawName = resolveEntryName({ header, pendingLongName, pendingPaxPath });\n pendingLongName = undefined;\n pendingPaxPath = undefined;\n const relativePath = toSafeRelativePath(rawName);\n if (relativePath !== null) {\n if (files.length + 1 > maxFiles) {\n throw new NpmTarError(\n `Package tarball exceeds max file count of ${maxFiles}. Aborting to prevent resource exhaustion.`,\n );\n }\n totalBytes += size;\n if (totalBytes > maxTotalBytes) {\n throw new NpmTarError(\n `Package tarball exceeds max total size of ${maxTotalBytes / 1024 / 1024}MB. Aborting to prevent resource exhaustion.`,\n );\n }\n files.push({\n relativePath,\n content: Buffer.from(tar.subarray(dataStart, dataEnd)),\n });\n }\n break;\n }\n case \"5\": {\n // Directory — created implicitly when files are written.\n pendingLongName = undefined;\n pendingPaxPath = undefined;\n break;\n }\n default: {\n // Symlinks, hardlinks, devices, FIFOs, ... are never materialized.\n const rawName = resolveEntryName({ header, pendingLongName, pendingPaxPath });\n pendingLongName = undefined;\n pendingPaxPath = undefined;\n onSkippedEntry?.(\n `Skipping unsupported tar entry type \"${typeflag}\" for \"${rawName}\" (only regular files are extracted).`,\n );\n break;\n }\n }\n\n offset = dataStart + Math.ceil(size / BLOCK_SIZE) * BLOCK_SIZE;\n }\n\n return files;\n}\n\nfunction isZeroBlock(block: Buffer): boolean {\n return block.every((byte) => byte === 0);\n}\n\n/** Cut a string at its first NUL character (tar fields are NUL-terminated). */\nfunction trimAtFirstNul(value: string): string {\n const nulIndex = value.indexOf(\"\\0\");\n return nulIndex === -1 ? value : value.substring(0, nulIndex);\n}\n\nfunction parseOctalField(block: Buffer, offset: number, length: number, field: string): number {\n const first = block[offset] ?? 0;\n if ((first & 0x80) !== 0) {\n throw new NpmTarError(`Unsupported tar archive: base-256 ${field} field is not supported`);\n }\n const raw = block.toString(\"latin1\", offset, offset + length);\n const text = trimAtFirstNul(raw).trim();\n if (text === \"\") {\n return 0;\n }\n if (!/^[0-7]+$/.test(text)) {\n throw new NpmTarError(`Invalid tar header: malformed octal ${field} field`);\n }\n return Number.parseInt(text, 8);\n}\n\n/**\n * Verify the ustar header checksum: the unsigned byte sum of the 512-byte\n * header with the checksum field itself treated as ASCII spaces.\n */\nfunction verifyHeaderChecksum(header: Buffer): void {\n const stored = parseOctalField(header, 148, 8, \"checksum\");\n let sum = 0;\n for (let i = 0; i < BLOCK_SIZE; i++) {\n sum += i >= 148 && i < 156 ? 0x20 : (header[i] ?? 0);\n }\n if (sum !== stored) {\n throw new NpmTarError(\"Invalid tar header: checksum mismatch\");\n }\n}\n\nfunction readCString(block: Buffer, offset: number, length: number): string {\n const end = block.indexOf(0, offset);\n const stop = end === -1 || end > offset + length ? offset + length : end;\n return block.toString(\"utf8\", offset, stop);\n}\n\nfunction resolveEntryName(params: {\n header: Buffer;\n pendingLongName: string | undefined;\n pendingPaxPath: string | undefined;\n}): string {\n const { header, pendingLongName, pendingPaxPath } = params;\n if (pendingPaxPath !== undefined) {\n return pendingPaxPath;\n }\n if (pendingLongName !== undefined) {\n return pendingLongName;\n }\n const name = readCString(header, 0, 100);\n const magic = header.toString(\"latin1\", 257, 262);\n const prefix = magic === \"ustar\" ? readCString(header, 345, 155) : \"\";\n return prefix.length > 0 ? `${prefix}/${name}` : name;\n}\n\n/**\n * Parse pax extended header records of the form `<len> <key>=<value>\\n`,\n * where `<len>` is the decimal length of the whole record.\n */\nfunction parsePaxRecords(data: Buffer): Map<string, string> {\n const records = new Map<string, string>();\n let offset = 0;\n while (offset < data.length) {\n if (data[offset] === 0) {\n break; // trailing NUL padding\n }\n const spaceIndex = data.indexOf(0x20, offset);\n if (spaceIndex === -1) {\n throw new NpmTarError(\"Invalid pax header: missing length delimiter\");\n }\n const recordLength = Number.parseInt(data.toString(\"utf8\", offset, spaceIndex), 10);\n if (\n !Number.isInteger(recordLength) ||\n recordLength <= 0 ||\n offset + recordLength > data.length\n ) {\n throw new NpmTarError(\"Invalid pax header: malformed record length\");\n }\n // Record content excludes the length prefix, the space, and the trailing newline.\n const record = data.toString(\"utf8\", spaceIndex + 1, offset + recordLength - 1);\n const equalsIndex = record.indexOf(\"=\");\n if (equalsIndex !== -1) {\n records.set(record.slice(0, equalsIndex), record.slice(equalsIndex + 1));\n }\n offset += recordLength;\n }\n return records;\n}\n\n/**\n * Validate a tar entry path and convert it to a package-root-relative path\n * with the first component stripped. Returns null for entries that resolve to\n * the package root itself (e.g. the `package/` folder entry). Throws on\n * traversal attempts.\n */\nfunction toSafeRelativePath(rawPath: string): string | null {\n if (rawPath.includes(\"\\0\")) {\n throw new NpmTarError(`Unsafe tar entry path (NUL byte): \"${rawPath}\"`);\n }\n if (rawPath.includes(\"\\\\\")) {\n throw new NpmTarError(`Unsafe tar entry path (backslash): \"${rawPath}\"`);\n }\n if (rawPath.startsWith(\"/\")) {\n throw new NpmTarError(`Unsafe tar entry path (absolute): \"${rawPath}\"`);\n }\n const segments = rawPath.split(\"/\").filter((segment) => segment !== \"\" && segment !== \".\");\n if (segments.includes(\"..\")) {\n throw new NpmTarError(`Unsafe tar entry path (\"..\" segment): \"${rawPath}\"`);\n }\n // Strip the tarball's single root folder (conventionally `package/`).\n segments.shift();\n if (segments.length === 0) {\n return null;\n }\n return segments.join(\"/\");\n}\n","import { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\n\nimport { optional, refine, z } from \"zod/mini\";\n\nimport { RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { fileExists, readFileContent, writeFileContent } from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\n/** Current lockfile format version. Bump when the schema changes. */\nexport const LOCKFILE_VERSION = 1;\n\n/**\n * Schema for a single locked skill entry with content integrity.\n */\nconst LockedSkillSchema = z.object({\n integrity: z.string(),\n});\nexport type LockedSkill = z.infer<typeof LockedSkillSchema>;\n\n/**\n * Schema for a single locked source entry.\n */\nconst LockedSourceSchema = z.object({\n requestedRef: optional(z.string()),\n resolvedRef: z\n .string()\n .check(refine((v) => /^[0-9a-f]{40}$/.test(v), \"resolvedRef must be a 40-character hex SHA\")),\n resolvedAt: optional(z.string()),\n skills: z.record(z.string(), LockedSkillSchema),\n});\nexport type LockedSource = z.infer<typeof LockedSourceSchema>;\n\n/**\n * Schema for the full lockfile (current version).\n */\nconst SourcesLockSchema = z.object({\n lockfileVersion: z.number(),\n sources: z.record(z.string(), LockedSourceSchema),\n});\nexport type SourcesLock = z.infer<typeof SourcesLockSchema>;\n\n/**\n * Schema for the legacy v0 lockfile format (skills as string array, no version field).\n */\nconst LegacyLockedSourceSchema = z.object({\n resolvedRef: z.string(),\n skills: z.array(z.string()),\n});\n\nconst LegacySourcesLockSchema = z.object({\n sources: z.record(z.string(), LegacyLockedSourceSchema),\n});\n\n/**\n * Migrate a legacy lockfile (string[] skills, no version) to the current format.\n * Skills get empty integrity since we can't compute it retroactively.\n */\nfunction migrateLegacyLock(params: {\n legacy: z.infer<typeof LegacySourcesLockSchema>;\n logger: Logger;\n}): SourcesLock {\n const { legacy, logger } = params;\n const sources: Record<string, LockedSource> = {};\n for (const [key, entry] of Object.entries(legacy.sources)) {\n const skills: Record<string, LockedSkill> = {};\n for (const name of entry.skills) {\n skills[name] = { integrity: \"\" };\n }\n sources[key] = {\n resolvedRef: entry.resolvedRef,\n skills,\n };\n }\n logger.info(\n \"Migrated legacy sources lockfile to version 1. Run 'rulesync install --update' to populate integrity hashes.\",\n );\n return { lockfileVersion: LOCKFILE_VERSION, sources };\n}\n\n/**\n * Create an empty lockfile structure.\n */\nexport function createEmptyLock(): SourcesLock {\n return { lockfileVersion: LOCKFILE_VERSION, sources: {} };\n}\n\n/**\n * Read the lockfile from disk.\n * @returns The parsed lockfile, or an empty lockfile if it doesn't exist or is invalid.\n */\nexport async function readLockFile(params: {\n projectRoot: string;\n logger: Logger;\n}): Promise<SourcesLock> {\n const { logger } = params;\n const lockPath = join(params.projectRoot, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);\n\n if (!(await fileExists(lockPath))) {\n logger.debug(\"No sources lockfile found, starting fresh.\");\n return createEmptyLock();\n }\n\n try {\n const content = await readFileContent(lockPath);\n const data = JSON.parse(content);\n\n // Try current schema first\n const result = SourcesLockSchema.safeParse(data);\n if (result.success) {\n return result.data;\n }\n\n // Try legacy schema (no lockfileVersion, skills as string[])\n const legacyResult = LegacySourcesLockSchema.safeParse(data);\n if (legacyResult.success) {\n return migrateLegacyLock({ legacy: legacyResult.data, logger });\n }\n\n logger.warn(\n `Invalid sources lockfile format (${RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`,\n );\n return createEmptyLock();\n } catch {\n logger.warn(\n `Failed to read sources lockfile (${RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH}). Starting fresh.`,\n );\n return createEmptyLock();\n }\n}\n\n/**\n * Write the lockfile to disk.\n */\nexport async function writeLockFile(params: {\n projectRoot: string;\n lock: SourcesLock;\n logger: Logger;\n}): Promise<void> {\n const { logger } = params;\n const lockPath = join(params.projectRoot, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);\n const content = JSON.stringify(params.lock, null, 2) + \"\\n\";\n await writeFileContent(lockPath, content);\n logger.debug(`Wrote sources lockfile to ${lockPath}`);\n}\n\n/**\n * Compute a SHA-256 integrity hash for a skill's contents.\n * Takes a sorted list of [relativePath, content] pairs to produce a deterministic hash.\n */\nexport function computeSkillIntegrity(files: Array<{ path: string; content: string }>): string {\n const hash = createHash(\"sha256\");\n // Sort by path for deterministic ordering\n const sorted = files.toSorted((a, b) => a.path.localeCompare(b.path));\n for (const file of sorted) {\n hash.update(file.path);\n hash.update(\"\\0\");\n hash.update(file.content);\n hash.update(\"\\0\");\n }\n return `sha256-${hash.digest(\"hex\")}`;\n}\n\n/**\n * Normalize a source key for consistent lockfile lookups.\n * Strips URL prefixes, provider prefixes, trailing slashes, .git suffix, and lowercases.\n */\nexport function normalizeSourceKey(source: string): string {\n let key = source;\n\n // Strip common URL prefixes\n for (const prefix of [\n \"https://www.github.com/\",\n \"https://github.com/\",\n \"http://www.github.com/\",\n \"http://github.com/\",\n \"https://www.gitlab.com/\",\n \"https://gitlab.com/\",\n \"http://www.gitlab.com/\",\n \"http://gitlab.com/\",\n ]) {\n if (key.toLowerCase().startsWith(prefix)) {\n key = key.substring(prefix.length);\n break;\n }\n }\n\n // Strip provider prefix\n for (const provider of [\"github:\", \"gitlab:\"]) {\n if (key.startsWith(provider)) {\n key = key.substring(provider.length);\n break;\n }\n }\n\n // Remove trailing slashes\n key = key.replace(/\\/+$/, \"\");\n\n // Remove .git suffix from repo\n key = key.replace(/\\.git$/, \"\");\n\n // Lowercase for case-insensitive matching\n key = key.toLowerCase();\n\n return key;\n}\n\n/**\n * Get the locked entry for a source key, if it exists.\n */\nexport function getLockedSource(lock: SourcesLock, sourceKey: string): LockedSource | undefined {\n const normalized = normalizeSourceKey(sourceKey);\n // Look up by normalized key\n for (const [key, value] of Object.entries(lock.sources)) {\n if (normalizeSourceKey(key) === normalized) {\n return value;\n }\n }\n return undefined;\n}\n\n/**\n * Set (or update) a locked entry for a source key.\n */\nexport function setLockedSource(\n lock: SourcesLock,\n sourceKey: string,\n entry: LockedSource,\n): SourcesLock {\n const normalized = normalizeSourceKey(sourceKey);\n // Remove any existing entries with the same normalized key\n const filteredSources: Record<string, LockedSource> = {};\n for (const [key, value] of Object.entries(lock.sources)) {\n if (normalizeSourceKey(key) !== normalized) {\n filteredSources[key] = value;\n }\n }\n return {\n lockfileVersion: lock.lockfileVersion,\n sources: {\n ...filteredSources,\n [normalized]: entry,\n },\n };\n}\n\n/**\n * Get the skill names from a locked source entry.\n */\nexport function getLockedSkillNames(entry: LockedSource): string[] {\n return Object.keys(entry.skills);\n}\n","import { join, posix, resolve, sep } from \"node:path\";\n\nimport { Semaphore } from \"es-toolkit/promise\";\n\nimport type { SourceEntry } from \"../config/config.js\";\nimport { SKILL_FILE_NAME } from \"../constants/general.js\";\nimport {\n FETCH_CONCURRENCY_LIMIT,\n MAX_FILE_SIZE,\n RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH,\n} from \"../constants/rulesync-paths.js\";\nimport { getLocalSkillDirNames } from \"../features/skills/skills-utils.js\";\nimport type { GitHubFileEntry, ParsedSource } from \"../types/fetch.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n directoryExists,\n removeDirectory,\n writeFileContent,\n} from \"../utils/file.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport {\n GitClientError,\n fetchSkillFiles,\n resolveDefaultRef,\n resolveRefToSha,\n validateRef,\n} from \"./git-client.js\";\nimport { GitHubClient, GitHubClientError, logGitHubAuthHints } from \"./github-client.js\";\nimport { listDirectoryRecursive, withSemaphore } from \"./github-utils.js\";\nimport {\n DEFAULT_NPM_REGISTRY_URL,\n fetchPackument,\n fetchTarball,\n getPackumentVersionDist,\n logNpmAuthHints,\n NpmClientError,\n resolveNpmToken,\n resolvePackumentVersion,\n shasumToSri,\n validateNpmPackageName,\n validateNpmRegistryUrl,\n verifyTarballIntegrity,\n} from \"./npm-client.js\";\nimport {\n createEmptyNpmLock,\n getNpmLockedSkillNames,\n getNpmLockedSource,\n type NpmLockedSource,\n type NpmSourcesLock,\n normalizeNpmSourceKey,\n readNpmLockFile,\n setNpmLockedSource,\n writeNpmLockFile,\n} from \"./npm-sources-lock.js\";\nimport { extractPackageTarball } from \"./npm-tar.js\";\nimport { parseSource } from \"./source-parser.js\";\nimport {\n type LockedSkill,\n type LockedSource,\n type SourcesLock,\n computeSkillIntegrity,\n createEmptyLock,\n getLockedSkillNames,\n getLockedSource,\n normalizeSourceKey,\n readLockFile,\n setLockedSource,\n writeLockFile,\n} from \"./sources-lock.js\";\n\nexport type ResolveAndFetchSourcesOptions = {\n /** Force re-resolve all refs, ignoring the lockfile. */\n updateSources?: boolean;\n /** Skip fetching entirely (use what's already on disk). */\n skipSources?: boolean;\n /** Fail if lockfile is missing or doesn't match sources (for CI). */\n frozen?: boolean;\n /** GitHub token for private repositories. */\n token?: string;\n};\n\nexport type ResolveAndFetchSourcesResult = {\n fetchedSkillCount: number;\n sourcesProcessed: number;\n};\n\ntype RemoteSkillFile = {\n relativePath: string;\n content: string;\n};\n\n/**\n * Resolve declared sources, fetch remote skills into .rulesync/skills/.curated/,\n * and update the lockfile.\n */\nexport async function resolveAndFetchSources(params: {\n sources: SourceEntry[];\n projectRoot: string;\n options?: ResolveAndFetchSourcesOptions;\n logger: Logger;\n}): Promise<ResolveAndFetchSourcesResult> {\n const { sources, projectRoot, options = {}, logger } = params;\n\n if (sources.length === 0) {\n return { fetchedSkillCount: 0, sourcesProcessed: 0 };\n }\n\n if (options.skipSources) {\n logger.info(\"Skipping source fetching.\");\n return { fetchedSkillCount: 0, sourcesProcessed: 0 };\n }\n\n // Read existing lockfiles. npm-transport sources are pinned in a separate\n // lockfile (`rulesync-npm.lock.json`) because they lock a package version +\n // tarball integrity instead of a git commit SHA.\n let lock: SourcesLock = options.updateSources\n ? createEmptyLock()\n : await readLockFile({ projectRoot, logger });\n let npmLock: NpmSourcesLock = options.updateSources\n ? createEmptyNpmLock()\n : await readNpmLockFile({ projectRoot, logger });\n\n // Frozen mode: validate lockfiles cover all declared sources.\n // Missing curated skills are fetched using locked refs.\n if (options.frozen) {\n assertFrozenLockCoversSources({ lock, npmLock, sources });\n }\n\n const originalLockJson = JSON.stringify(lock);\n const originalNpmLockJson = JSON.stringify(npmLock);\n\n // Resolve GitHub token\n const token = GitHubClient.resolveToken(options.token);\n const client = new GitHubClient({ token });\n\n // Determine local skills (in .rulesync/skills/ but not in .curated/)\n const localSkillNames = await getLocalSkillDirNames(projectRoot);\n\n let totalSkillCount = 0;\n const allFetchedSkillNames = new Set<string>();\n\n for (const sourceEntry of sources) {\n try {\n const result = await fetchSingleSource({\n sourceEntry,\n client,\n projectRoot,\n lock,\n npmLock,\n localSkillNames,\n alreadyFetchedSkillNames: allFetchedSkillNames,\n updateSources: options.updateSources ?? false,\n frozen: options.frozen ?? false,\n logger,\n });\n\n lock = result.lock;\n npmLock = result.npmLock;\n totalSkillCount += result.skillCount;\n for (const name of result.fetchedSkillNames) {\n allFetchedSkillNames.add(name);\n }\n } catch (error) {\n logSourceFetchFailure({ sourceEntry, error, logger });\n }\n }\n\n lock = pruneStaleLockEntries({ lock, sources, logger });\n npmLock = pruneStaleNpmLockEntries({ npmLock, sources, logger });\n\n await writeLockFilesIfChanged({\n projectRoot,\n lock,\n npmLock,\n originalLockJson,\n originalNpmLockJson,\n frozen: options.frozen ?? false,\n logger,\n });\n\n return { fetchedSkillCount: totalSkillCount, sourcesProcessed: sources.length };\n}\n\n/**\n * Dispatch a single source to the npm fetcher or the git/github fetcher,\n * returning the (possibly) updated lock objects for both lockfiles.\n */\nasync function fetchSingleSource(params: {\n sourceEntry: SourceEntry;\n client: GitHubClient;\n projectRoot: string;\n lock: SourcesLock;\n npmLock: NpmSourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n frozen: boolean;\n logger: Logger;\n}): Promise<{\n skillCount: number;\n fetchedSkillNames: string[];\n lock: SourcesLock;\n npmLock: NpmSourcesLock;\n}> {\n const { sourceEntry, lock, npmLock } = params;\n if ((sourceEntry.transport ?? \"github\") === \"npm\") {\n const result = await fetchSourceViaNpm({\n sourceEntry,\n projectRoot: params.projectRoot,\n npmLock,\n localSkillNames: params.localSkillNames,\n alreadyFetchedSkillNames: params.alreadyFetchedSkillNames,\n updateSources: params.updateSources,\n logger: params.logger,\n });\n return {\n skillCount: result.skillCount,\n fetchedSkillNames: result.fetchedSkillNames,\n lock,\n npmLock: result.updatedLock,\n };\n }\n const result = await fetchSourceByTransport({\n sourceEntry,\n client: params.client,\n projectRoot: params.projectRoot,\n lock,\n localSkillNames: params.localSkillNames,\n alreadyFetchedSkillNames: params.alreadyFetchedSkillNames,\n updateSources: params.updateSources,\n frozen: params.frozen,\n logger: params.logger,\n });\n return {\n skillCount: result.skillCount,\n fetchedSkillNames: result.fetchedSkillNames,\n lock: result.updatedLock,\n npmLock,\n };\n}\n\n/** Log a per-source fetch failure with transport-specific troubleshooting hints. */\nfunction logSourceFetchFailure(params: {\n sourceEntry: SourceEntry;\n error: unknown;\n logger: Logger;\n}): void {\n const { sourceEntry, error, logger } = params;\n logger.error(`Failed to fetch source \"${sourceEntry.source}\": ${formatError(error)}`);\n if (error instanceof GitHubClientError) {\n logGitHubAuthHints({ error, logger });\n } else if (error instanceof GitClientError) {\n logGitClientHints({ error, logger });\n } else if (error instanceof NpmClientError) {\n logNpmAuthHints({ error, logger });\n }\n}\n\n/** Write each lockfile only when it changed (and never in frozen mode). */\nasync function writeLockFilesIfChanged(params: {\n projectRoot: string;\n lock: SourcesLock;\n npmLock: NpmSourcesLock;\n originalLockJson: string;\n originalNpmLockJson: string;\n frozen: boolean;\n logger: Logger;\n}): Promise<void> {\n const { projectRoot, lock, npmLock, originalLockJson, originalNpmLockJson, frozen, logger } =\n params;\n if (!frozen && JSON.stringify(lock) !== originalLockJson) {\n await writeLockFile({ projectRoot, lock, logger });\n } else {\n logger.debug(\"Lockfile unchanged, skipping write.\");\n }\n if (!frozen && JSON.stringify(npmLock) !== originalNpmLockJson) {\n await writeNpmLockFile({ projectRoot, lock: npmLock, logger });\n } else {\n logger.debug(\"npm lockfile unchanged, skipping write.\");\n }\n}\n\n/**\n * Log contextual hints for GitClientError to help users troubleshoot.\n */\nfunction logGitClientHints(params: { error: GitClientError; logger: Logger }): void {\n const { error, logger } = params;\n if (error.message.includes(\"not installed\")) {\n logger.info(\"Hint: Install git and ensure it is available on your PATH.\");\n } else {\n logger.info(\"Hint: Check your git credentials (SSH keys, credential helper, or access token).\");\n }\n}\n\n/**\n * Frozen mode: validate the lockfiles cover every declared source. Throws with\n * remediation guidance listing any uncovered source keys. npm-transport\n * sources are checked against the npm lockfile; everything else against the\n * main sources lockfile.\n */\nfunction assertFrozenLockCoversSources(params: {\n lock: SourcesLock;\n npmLock: NpmSourcesLock;\n sources: SourceEntry[];\n}): void {\n const { lock, npmLock, sources } = params;\n const missingKeys: string[] = [];\n\n for (const source of sources) {\n const locked =\n (source.transport ?? \"github\") === \"npm\"\n ? getNpmLockedSource(npmLock, source.source)\n : getLockedSource(lock, source.source);\n if (!locked) {\n missingKeys.push(source.source);\n }\n }\n if (missingKeys.length > 0) {\n throw new Error(\n `Frozen install failed: lockfile is missing entries for: ${missingKeys.join(\", \")}. Run 'rulesync install' to update the lockfile.`,\n );\n }\n}\n\n/**\n * Dispatch a single source to the transport-specific fetcher (git CLI vs.\n * GitHub REST API), preserving the original default of \"github\".\n */\nasync function fetchSourceByTransport(params: {\n sourceEntry: SourceEntry;\n client: GitHubClient;\n projectRoot: string;\n lock: SourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n frozen: boolean;\n logger: Logger;\n}): Promise<{ skillCount: number; fetchedSkillNames: string[]; updatedLock: SourcesLock }> {\n const {\n sourceEntry,\n client,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n frozen,\n logger,\n } = params;\n const transport = sourceEntry.transport ?? \"github\";\n if (transport === \"git\") {\n return fetchSourceViaGit({\n sourceEntry,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n frozen,\n logger,\n });\n }\n return fetchSource({\n sourceEntry,\n client,\n projectRoot,\n lock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n logger,\n });\n}\n\n/**\n * Prune stale lockfile entries whose keys are not in the current sources\n * (immutable — returns a fresh lock object).\n */\nfunction pruneStaleLockEntries(params: {\n lock: SourcesLock;\n sources: SourceEntry[];\n logger: Logger;\n}): SourcesLock {\n const { lock, sources, logger } = params;\n const sourceKeys = new Set(\n sources\n .filter((s) => (s.transport ?? \"github\") !== \"npm\")\n .map((s) => normalizeSourceKey(s.source)),\n );\n const prunedSources: typeof lock.sources = {};\n for (const [key, value] of Object.entries(lock.sources)) {\n if (sourceKeys.has(normalizeSourceKey(key))) {\n prunedSources[key] = value;\n } else {\n logger.debug(`Pruned stale lockfile entry: ${key}`);\n }\n }\n return { lockfileVersion: lock.lockfileVersion, sources: prunedSources };\n}\n\n/**\n * Prune stale npm lockfile entries whose keys are not in the current\n * npm-transport sources (immutable — returns a fresh lock object).\n */\nfunction pruneStaleNpmLockEntries(params: {\n npmLock: NpmSourcesLock;\n sources: SourceEntry[];\n logger: Logger;\n}): NpmSourcesLock {\n const { npmLock, sources, logger } = params;\n const sourceKeys = new Set(\n sources\n .filter((s) => (s.transport ?? \"github\") === \"npm\")\n .map((s) => normalizeNpmSourceKey(s.source)),\n );\n const prunedSources: typeof npmLock.sources = {};\n for (const [key, value] of Object.entries(npmLock.sources)) {\n if (sourceKeys.has(normalizeNpmSourceKey(key))) {\n prunedSources[key] = value;\n } else {\n logger.debug(`Pruned stale npm lockfile entry: ${key}`);\n }\n }\n return { lockfileVersion: npmLock.lockfileVersion, sources: prunedSources };\n}\n\n/**\n * Check if all locked skills exist on disk in the curated directory.\n */\nasync function checkLockedSkillsExist(curatedDir: string, skillNames: string[]): Promise<boolean> {\n if (skillNames.length === 0) return true;\n for (const name of skillNames) {\n if (!(await directoryExists(join(curatedDir, name)))) {\n return false;\n }\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers for fetchSource and fetchSourceViaGit\n// ---------------------------------------------------------------------------\n\n/**\n * Remove previously curated skill directories for a source before re-fetching.\n * Validates that each path resolves within the curated directory to prevent traversal.\n */\nasync function cleanPreviousCuratedSkills(params: {\n curatedDir: string;\n lockedSkillNames: string[];\n logger: Logger;\n}): Promise<void> {\n const { curatedDir, lockedSkillNames, logger } = params;\n const resolvedCuratedDir = resolve(curatedDir);\n for (const prevSkill of lockedSkillNames) {\n const prevDir = join(curatedDir, prevSkill);\n if (!resolve(prevDir).startsWith(resolvedCuratedDir + sep)) {\n logger.warn(\n `Skipping removal of \"${prevSkill}\": resolved path is outside the curated directory.`,\n );\n continue;\n }\n if (await directoryExists(prevDir)) {\n await removeDirectory(prevDir);\n }\n }\n}\n\n/**\n * Check whether a skill should be skipped during fetching.\n * Returns true (with appropriate logging) if the skill should be skipped.\n */\nfunction shouldSkipSkill(params: {\n skillName: string;\n sourceKey: string;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n logger: Logger;\n}): boolean {\n const { skillName, sourceKey, localSkillNames, alreadyFetchedSkillNames, logger } = params;\n if (skillName.includes(\"..\") || skillName.includes(\"/\") || skillName.includes(\"\\\\\")) {\n logger.warn(\n `Skipping skill with invalid name \"${skillName}\" from ${sourceKey}: contains path traversal characters.`,\n );\n return true;\n }\n if (localSkillNames.has(skillName)) {\n logger.debug(\n `Skipping remote skill \"${skillName}\" from ${sourceKey}: local skill takes precedence.`,\n );\n return true;\n }\n if (alreadyFetchedSkillNames.has(skillName)) {\n logger.warn(\n `Skipping duplicate skill \"${skillName}\" from ${sourceKey}: already fetched from another source.`,\n );\n return true;\n }\n return false;\n}\n\n/**\n * Write skill files to disk, compute integrity, and check against the lockfile.\n * Returns the computed LockedSkill entry.\n */\nasync function writeSkillAndComputeIntegrity(params: {\n skillName: string;\n files: Array<{ relativePath: string; content: string }>;\n curatedDir: string;\n locked: LockedSource | undefined;\n resolvedSha: string;\n sourceKey: string;\n logger: Logger;\n}): Promise<LockedSkill> {\n const { skillName, files, curatedDir, locked, resolvedSha, sourceKey, logger } = params;\n const written: Array<{ path: string; content: string }> = [];\n\n for (const file of files) {\n checkPathTraversal({\n relativePath: file.relativePath,\n intendedRootDir: join(curatedDir, skillName),\n });\n await writeFileContent(join(curatedDir, skillName, file.relativePath), file.content);\n written.push({ path: file.relativePath, content: file.content });\n }\n\n const integrity = computeSkillIntegrity(written);\n const lockedSkillEntry = locked?.skills[skillName];\n if (\n lockedSkillEntry?.integrity &&\n lockedSkillEntry.integrity !== integrity &&\n resolvedSha === locked?.resolvedRef\n ) {\n logger.warn(\n `Integrity mismatch for skill \"${skillName}\" from ${sourceKey}: expected \"${lockedSkillEntry.integrity}\", got \"${integrity}\". Content may have been tampered with.`,\n );\n }\n\n return { integrity };\n}\n\n/**\n * Merge back locked skills that still exist in the remote but were skipped\n * during fetching (due to local precedence, already-fetched, etc.). Skills no\n * longer present in the remote (e.g. renamed or deleted upstream) are\n * intentionally dropped. Shared by the git/github and npm lock updates.\n */\nfunction mergeFetchedWithLockedSkills(params: {\n fetchedSkills: Record<string, LockedSkill>;\n lockedSkills: Record<string, LockedSkill> | undefined;\n remoteSkillNames: string[];\n}): Record<string, LockedSkill> {\n const { fetchedSkills, lockedSkills, remoteSkillNames } = params;\n const remoteSet = new Set(remoteSkillNames);\n const mergedSkills: Record<string, LockedSkill> = { ...fetchedSkills };\n if (lockedSkills) {\n for (const [skillName, skillEntry] of Object.entries(lockedSkills)) {\n if (!(skillName in mergedSkills) && remoteSet.has(skillName)) {\n mergedSkills[skillName] = skillEntry;\n }\n }\n }\n return mergedSkills;\n}\n\n/**\n * Merge newly fetched skills with existing locked skills and update the lockfile.\n */\nfunction buildLockUpdate(params: {\n lock: SourcesLock;\n sourceKey: string;\n fetchedSkills: Record<string, LockedSkill>;\n locked: LockedSource | undefined;\n requestedRef: string | undefined;\n resolvedSha: string;\n remoteSkillNames: string[];\n logger: Logger;\n}): { updatedLock: SourcesLock; fetchedNames: string[] } {\n const {\n lock,\n sourceKey,\n fetchedSkills,\n locked,\n requestedRef,\n resolvedSha,\n remoteSkillNames,\n logger,\n } = params;\n const fetchedNames = Object.keys(fetchedSkills);\n\n const mergedSkills = mergeFetchedWithLockedSkills({\n fetchedSkills,\n lockedSkills: locked?.skills,\n remoteSkillNames,\n });\n\n const updatedLock = setLockedSource(lock, sourceKey, {\n requestedRef,\n resolvedRef: resolvedSha,\n resolvedAt: new Date().toISOString(),\n skills: mergedSkills,\n });\n\n logger.info(\n `Fetched ${fetchedNames.length} skill(s) from ${sourceKey}: ${fetchedNames.join(\", \") || \"(none)\"}`,\n );\n\n return { updatedLock, fetchedNames };\n}\n\nfunction getFirstPathSeparatorIndex(path: string): number {\n const slashIndex = path.indexOf(\"/\");\n const backslashIndex = path.indexOf(\"\\\\\");\n if (slashIndex === -1) return backslashIndex;\n if (backslashIndex === -1) return slashIndex;\n return Math.min(slashIndex, backslashIndex);\n}\n\n/**\n * Decide whether a repository's root-level files should be installed as the\n * single requested skill (the \"root fallback\").\n *\n * A root fallback fires only when a single, non-wildcard skill was requested,\n * that skill's own directory is absent, and the repository root actually carries\n * a `SKILL.md`. Both the git transport (`groupRemoteFilesBySkillRoot`) and the\n * GitHub transport (`discoverGithubSkillDirs`) gate on these same conditions, so\n * the decision lives here to keep the two paths from drifting.\n */\nfunction shouldUseRootFallback(params: {\n skillFilter: string[];\n isWildcard: boolean;\n hasRootSkillFile: boolean;\n hasRequestedSkillDir: boolean;\n}): boolean {\n const { skillFilter, isWildcard, hasRootSkillFile, hasRequestedSkillDir } = params;\n const [singleSkillName] = skillFilter;\n return (\n !isWildcard &&\n skillFilter.length === 1 &&\n singleSkillName !== undefined &&\n hasRootSkillFile &&\n !hasRequestedSkillDir\n );\n}\n\nfunction groupRemoteFilesBySkillRoot(params: {\n remoteFiles: RemoteSkillFile[];\n skillFilter: string[];\n isWildcard: boolean;\n}): Map<string, RemoteSkillFile[]> {\n const { remoteFiles, skillFilter, isWildcard } = params;\n const grouped = new Map<string, RemoteSkillFile[]>();\n const rootLevelFiles: RemoteSkillFile[] = [];\n\n for (const file of remoteFiles) {\n const separatorIndex = getFirstPathSeparatorIndex(file.relativePath);\n if (separatorIndex === -1) {\n rootLevelFiles.push(file);\n continue;\n }\n\n const skillName = file.relativePath.substring(0, separatorIndex);\n if (skillName.length === 0) {\n continue;\n }\n\n const innerPath = file.relativePath.substring(separatorIndex + 1);\n const groupedFiles = grouped.get(skillName) ?? [];\n groupedFiles.push({ relativePath: innerPath, content: file.content });\n grouped.set(skillName, groupedFiles);\n }\n\n const [singleSkillName] = skillFilter;\n const hasRootSkillFile = rootLevelFiles.some((file) => file.relativePath === SKILL_FILE_NAME);\n if (\n singleSkillName !== undefined &&\n shouldUseRootFallback({\n skillFilter,\n isWildcard,\n hasRootSkillFile,\n hasRequestedSkillDir: grouped.has(singleSkillName),\n })\n ) {\n grouped.set(singleSkillName, rootLevelFiles);\n }\n\n return grouped;\n}\n\n// ---------------------------------------------------------------------------\n// Transport-specific fetch functions\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a GitHub source's ref to a commit SHA, preferring the locked SHA for\n * deterministic fetches and otherwise resolving the declared ref or default\n * branch. Returns the on-disk `ref` (SHA when freshly resolved, else locked\n * ref), the resolved SHA, and the requested ref.\n */\nasync function resolveGithubFetchRef(params: {\n parsed: ParsedSource;\n locked: LockedSource | undefined;\n updateSources: boolean;\n sourceKey: string;\n client: GitHubClient;\n logger: Logger;\n}): Promise<{ ref: string; resolvedSha: string; requestedRef: string | undefined }> {\n const { parsed, locked, updateSources, sourceKey, client, logger } = params;\n if (locked && !updateSources) {\n // Use the locked SHA for deterministic fetching\n logger.debug(`Using locked ref for ${sourceKey}: ${locked.resolvedRef}`);\n return {\n ref: locked.resolvedRef,\n resolvedSha: locked.resolvedRef,\n requestedRef: locked.requestedRef,\n };\n }\n // Resolve the ref (or default branch) to a SHA\n const requestedRef = parsed.ref ?? (await client.getDefaultBranch(parsed.owner, parsed.repo));\n const resolvedSha = await client.resolveRefToSha(parsed.owner, parsed.repo, requestedRef);\n logger.debug(`Resolved ${sourceKey} ref \"${requestedRef}\" to SHA: ${resolvedSha}`);\n return { ref: resolvedSha, resolvedSha, requestedRef };\n}\n\n/**\n * Fallback path used when an explicit single-skill source points at a flat skill\n * with root-level files. Fetches and writes that skill into `fetchedSkills`.\n * Returns whether the fallback fired and the resulting remote skill names.\n */\nasync function fetchRootLevelFallbackSkill(params: {\n entries: GitHubFileEntry[];\n parsed: ParsedSource;\n ref: string;\n resolvedSha: string;\n skillFilter: string[];\n isWildcard: boolean;\n curatedDir: string;\n locked: LockedSource | undefined;\n sourceKey: string;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n client: GitHubClient;\n semaphore: Semaphore;\n fetchedSkills: Record<string, LockedSkill>;\n logger: Logger;\n}): Promise<{ handled: boolean; remoteSkillNames: string[] }> {\n const {\n entries,\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n } = params;\n\n const rootFiles = entries.filter((entry) => entry.type === \"file\");\n const rootSkillFiles: RemoteSkillFile[] = [];\n\n for (const file of rootFiles) {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping file \"${file.path}\" (${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n continue;\n }\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, file.path, ref),\n );\n rootSkillFiles.push({ relativePath: file.name, content });\n }\n\n const groupedRootFiles = groupRemoteFilesBySkillRoot({\n remoteFiles: rootSkillFiles,\n skillFilter,\n isWildcard,\n });\n const [fallbackSkillName] = groupedRootFiles.keys();\n if (fallbackSkillName === undefined) {\n return { handled: false, remoteSkillNames: [] };\n }\n\n if (\n !shouldSkipSkill({\n skillName: fallbackSkillName,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n fetchedSkills[fallbackSkillName] = await writeSkillAndComputeIntegrity({\n skillName: fallbackSkillName,\n files: groupedRootFiles.get(fallbackSkillName) ?? [],\n curatedDir,\n locked,\n resolvedSha,\n sourceKey,\n logger,\n });\n logger.debug(`Fetched skill \"${fallbackSkillName}\" from ${sourceKey}`);\n }\n\n return { handled: true, remoteSkillNames: [fallbackSkillName] };\n}\n\n/**\n * Recursively fetch and write a single skill directory's files via the GitHub\n * REST API, returning its computed LockedSkill entry.\n */\nasync function fetchGithubSkillDir(params: {\n skillDir: { name: string; path: string };\n parsed: ParsedSource;\n ref: string;\n resolvedSha: string;\n curatedDir: string;\n locked: LockedSource | undefined;\n sourceKey: string;\n client: GitHubClient;\n semaphore: Semaphore;\n logger: Logger;\n}): Promise<LockedSkill> {\n const {\n skillDir,\n parsed,\n ref,\n resolvedSha,\n curatedDir,\n locked,\n sourceKey,\n client,\n semaphore,\n logger,\n } = params;\n\n // Recursively fetch all files in this skill directory\n const allFiles = await listDirectoryRecursive({\n client,\n owner: parsed.owner,\n repo: parsed.repo,\n path: skillDir.path,\n ref,\n semaphore,\n });\n\n // Filter out files exceeding MAX_FILE_SIZE\n const files = allFiles.filter((file) => {\n if (file.size > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping file \"${file.path}\" (${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n return false;\n }\n return true;\n });\n\n // Fetch all file contents\n const skillFiles: Array<{ relativePath: string; content: string }> = [];\n for (const file of files) {\n const relativeToSkill = file.path.substring(skillDir.path.length + 1);\n const content = await withSemaphore(semaphore, () =>\n client.getFileContent(parsed.owner, parsed.repo, file.path, ref),\n );\n skillFiles.push({ relativePath: relativeToSkill, content });\n }\n\n return writeSkillAndComputeIntegrity({\n skillName: skillDir.name,\n files: skillFiles,\n curatedDir,\n locked,\n resolvedSha,\n sourceKey,\n logger,\n });\n}\n\n/**\n * List the remote skills directory and apply the root-level fallback. Returns a\n * `notFound` sentinel when the directory 404s (so the caller can skip the\n * source), otherwise the discovered skill subdirectories plus any fallback skill\n * names already written into `fetchedSkills`.\n */\nasync function discoverGithubSkillDirs(params: {\n parsed: ParsedSource;\n ref: string;\n resolvedSha: string;\n skillFilter: string[];\n isWildcard: boolean;\n curatedDir: string;\n locked: LockedSource | undefined;\n sourceKey: string;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n client: GitHubClient;\n semaphore: Semaphore;\n fetchedSkills: Record<string, LockedSkill>;\n logger: Logger;\n}): Promise<\n | { status: \"notFound\" }\n | {\n status: \"ok\";\n remoteSkillDirs: Array<{ name: string; path: string }>;\n fallbackHandled: boolean;\n remoteSkillNames: string[];\n }\n> {\n const {\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n } = params;\n\n const skillsBasePath = parsed.path ?? \"skills\";\n try {\n const entries = await client.listDirectory(parsed.owner, parsed.repo, skillsBasePath, ref);\n const remoteSkillDirs = entries\n .filter((e) => e.type === \"dir\")\n .map((e) => ({ name: e.name, path: e.path }));\n\n const [singleSkillName] = skillFilter;\n const hasRequestedSkillDir =\n singleSkillName !== undefined && remoteSkillDirs.some((d) => d.name === singleSkillName);\n // Detect a root-level SKILL.md from the directory listing we already have, so\n // the fallback (and its full root-file fetch) is skipped when there is no\n // root skill to install — not just when the requested dir is absent.\n const hasRootSkillFile = entries.some(\n (entry) => entry.type === \"file\" && entry.name === SKILL_FILE_NAME,\n );\n if (\n shouldUseRootFallback({ skillFilter, isWildcard, hasRootSkillFile, hasRequestedSkillDir })\n ) {\n const fallback = await fetchRootLevelFallbackSkill({\n entries,\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n });\n if (fallback.handled) {\n return {\n status: \"ok\",\n remoteSkillDirs,\n fallbackHandled: true,\n remoteSkillNames: fallback.remoteSkillNames,\n };\n }\n }\n\n return { status: \"ok\", remoteSkillDirs, fallbackHandled: false, remoteSkillNames: [] };\n } catch (error) {\n if (error instanceof GitHubClientError && error.statusCode === 404) {\n return { status: \"notFound\" };\n }\n throw error;\n }\n}\n\n/**\n * Fetch skills from a single source entry via the GitHub REST API.\n */\nasync function fetchSource(params: {\n sourceEntry: SourceEntry;\n client: GitHubClient;\n projectRoot: string;\n lock: SourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n logger: Logger;\n}): Promise<{\n skillCount: number;\n fetchedSkillNames: string[];\n updatedLock: SourcesLock;\n}> {\n const {\n sourceEntry,\n client,\n projectRoot,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n logger,\n } = params;\n const { lock } = params;\n\n const parsed = parseSource(sourceEntry.source);\n\n if (parsed.provider === \"gitlab\") {\n logger.warn(`GitLab sources are not yet supported. Skipping \"${sourceEntry.source}\".`);\n return { skillCount: 0, fetchedSkillNames: [], updatedLock: lock };\n }\n\n const sourceKey = sourceEntry.source;\n const locked = getLockedSource(lock, sourceKey);\n const lockedSkillNames = locked ? getLockedSkillNames(locked) : [];\n\n // Resolve the ref to a commit SHA\n const { ref, resolvedSha, requestedRef } = await resolveGithubFetchRef({\n parsed,\n locked,\n updateSources,\n sourceKey,\n client,\n logger,\n });\n\n const curatedDir = join(projectRoot, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);\n\n // Skip re-fetch if SHA matches lockfile and curated skills exist on disk\n if (locked && resolvedSha === locked.resolvedRef && !updateSources) {\n const allExist = await checkLockedSkillsExist(curatedDir, lockedSkillNames);\n if (allExist) {\n logger.debug(`SHA unchanged for ${sourceKey}, skipping re-fetch.`);\n return {\n skillCount: 0,\n fetchedSkillNames: lockedSkillNames,\n updatedLock: lock,\n };\n }\n }\n\n // Determine which skills to fetch\n const skillFilter = sourceEntry.skills ?? [\"*\"];\n const isWildcard = skillFilter.length === 1 && skillFilter[0] === \"*\";\n const semaphore = new Semaphore(FETCH_CONCURRENCY_LIMIT);\n const fetchedSkills: Record<string, LockedSkill> = {};\n\n // List the skills/ directory in the remote repo.\n // If a path is given in the source URL, it points directly to the skills directory.\n // Otherwise, look for \"skills/\" at the repo root.\n const discovery = await discoverGithubSkillDirs({\n parsed,\n ref,\n resolvedSha,\n skillFilter,\n isWildcard,\n curatedDir,\n locked,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n client,\n semaphore,\n fetchedSkills,\n logger,\n });\n if (discovery.status === \"notFound\") {\n logger.warn(`No skills/ directory found in ${sourceKey}. Skipping.`);\n return { skillCount: 0, fetchedSkillNames: [], updatedLock: lock };\n }\n const { remoteSkillDirs, fallbackHandled, remoteSkillNames: fallbackSkillNames } = discovery;\n\n // Filter skills by name\n const filteredDirs = isWildcard\n ? remoteSkillDirs\n : remoteSkillDirs.filter((d) => skillFilter.includes(d.name));\n const remoteSkillNames = fallbackHandled ? fallbackSkillNames : filteredDirs.map((d) => d.name);\n\n if (locked) {\n await cleanPreviousCuratedSkills({ curatedDir, lockedSkillNames, logger });\n }\n\n for (const skillDir of filteredDirs) {\n if (\n shouldSkipSkill({\n skillName: skillDir.name,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n continue;\n }\n\n fetchedSkills[skillDir.name] = await fetchGithubSkillDir({\n skillDir,\n parsed,\n ref,\n resolvedSha,\n curatedDir,\n locked,\n sourceKey,\n client,\n semaphore,\n logger,\n });\n logger.debug(`Fetched skill \"${skillDir.name}\" from ${sourceKey}`);\n }\n\n const result = buildLockUpdate({\n lock,\n sourceKey,\n fetchedSkills,\n locked,\n requestedRef,\n resolvedSha,\n remoteSkillNames,\n logger,\n });\n\n return {\n skillCount: result.fetchedNames.length,\n fetchedSkillNames: result.fetchedNames,\n updatedLock: result.updatedLock,\n };\n}\n\n/**\n * Fetch skills from a single source using git CLI (works with any git remote).\n */\nasync function fetchSourceViaGit(params: {\n sourceEntry: SourceEntry;\n projectRoot: string;\n lock: SourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n frozen: boolean;\n logger: Logger;\n}): Promise<{ skillCount: number; fetchedSkillNames: string[]; updatedLock: SourcesLock }> {\n const {\n sourceEntry,\n projectRoot,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n frozen,\n logger,\n } = params;\n const { lock } = params;\n const url = sourceEntry.source;\n const locked = getLockedSource(lock, url);\n const lockedSkillNames = locked ? getLockedSkillNames(locked) : [];\n\n let resolvedSha: string;\n let requestedRef: string | undefined;\n if (locked && !updateSources) {\n resolvedSha = locked.resolvedRef;\n requestedRef = locked.requestedRef;\n // Validate locked ref before passing to git commands\n if (requestedRef) {\n validateRef(requestedRef);\n }\n } else if (sourceEntry.ref) {\n requestedRef = sourceEntry.ref;\n resolvedSha = await resolveRefToSha(url, requestedRef);\n } else {\n const def = await resolveDefaultRef(url);\n requestedRef = def.ref;\n resolvedSha = def.sha;\n }\n\n const curatedDir = join(projectRoot, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);\n if (locked && resolvedSha === locked.resolvedRef && !updateSources) {\n if (await checkLockedSkillsExist(curatedDir, lockedSkillNames)) {\n return { skillCount: 0, fetchedSkillNames: lockedSkillNames, updatedLock: lock };\n }\n }\n\n // Resolve requestedRef lazily (deferred from locked path to avoid unnecessary network calls)\n if (!requestedRef) {\n if (frozen) {\n throw new Error(\n `Frozen install failed: lockfile entry for \"${url}\" is missing requestedRef. Run 'rulesync install' to update the lockfile.`,\n );\n }\n const def = await resolveDefaultRef(url);\n requestedRef = def.ref;\n resolvedSha = def.sha;\n }\n\n const skillFilter = sourceEntry.skills ?? [\"*\"];\n const isWildcard = skillFilter.length === 1 && skillFilter[0] === \"*\";\n const remoteFiles = await fetchSkillFiles({\n url,\n ref: requestedRef,\n skillsPath: sourceEntry.path ?? \"skills\",\n });\n\n const skillFileMap = groupRemoteFilesBySkillRoot({ remoteFiles, skillFilter, isWildcard });\n\n const allNames = [...skillFileMap.keys()];\n const filteredNames = isWildcard ? allNames : allNames.filter((n) => skillFilter.includes(n));\n\n if (locked) {\n await cleanPreviousCuratedSkills({ curatedDir, lockedSkillNames, logger });\n }\n\n const fetchedSkills: Record<string, LockedSkill> = {};\n for (const skillName of filteredNames) {\n if (\n shouldSkipSkill({\n skillName,\n sourceKey: url,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n continue;\n }\n\n fetchedSkills[skillName] = await writeSkillAndComputeIntegrity({\n skillName,\n files: skillFileMap.get(skillName) ?? [],\n curatedDir,\n locked,\n resolvedSha,\n sourceKey: url,\n logger,\n });\n }\n\n const result = buildLockUpdate({\n lock,\n sourceKey: url,\n fetchedSkills,\n locked,\n requestedRef,\n resolvedSha,\n remoteSkillNames: filteredNames,\n logger,\n });\n return {\n skillCount: result.fetchedNames.length,\n fetchedSkillNames: result.fetchedNames,\n updatedLock: result.updatedLock,\n };\n}\n\n// ---------------------------------------------------------------------------\n// npm transport (EXPERIMENTAL)\n// ---------------------------------------------------------------------------\n\n/**\n * Select the skill files inside an extracted npm package, mirroring the git\n * transport's discovery: files under `skills/` (or the configured `path`) are\n * grouped per subdirectory; a package whose `SKILL.md` sits at the package\n * root is installed as a single skill (root fallback via\n * {@link shouldUseRootFallback}), named after the requested skill or, for\n * wildcard fetches, after the package's base name.\n */\nfunction selectNpmSkillFiles(params: {\n allFiles: RemoteSkillFile[];\n skillsPath: string;\n skillFilter: string[];\n isWildcard: boolean;\n packageName: string;\n}): { remoteFiles: RemoteSkillFile[]; skillFilter: string[]; isWildcard: boolean } {\n const { allFiles, skillsPath, skillFilter, isWildcard, packageName } = params;\n\n const normalizedBase = posix.normalize(skillsPath.replace(/\\\\/g, \"/\")).replace(/\\/+$/, \"\");\n const isRootPath = normalizedBase === \"\" || normalizedBase === \".\";\n if (isRootPath) {\n return { remoteFiles: allFiles, skillFilter, isWildcard };\n }\n\n const prefix = `${normalizedBase}/`;\n const filesUnderBase = allFiles\n .filter((file) => file.relativePath.startsWith(prefix))\n .map((file) => ({\n relativePath: file.relativePath.substring(prefix.length),\n content: file.content,\n }));\n if (filesUnderBase.length > 0) {\n return { remoteFiles: filesUnderBase, skillFilter, isWildcard };\n }\n\n // Root fallback: the package itself is a single skill with SKILL.md at its\n // root. For wildcard fetches the skill name is derived from the package\n // base name (scope stripped), so `@acme/my-skill` installs as `my-skill`.\n const hasRootSkillFile = allFiles.some((file) => file.relativePath === SKILL_FILE_NAME);\n const fallbackFilter = isWildcard ? [npmPackageBaseName(packageName)] : skillFilter;\n const [singleSkillName] = fallbackFilter;\n if (\n fallbackFilter.length === 1 &&\n singleSkillName !== undefined &&\n shouldUseRootFallback({\n skillFilter: fallbackFilter,\n isWildcard: false,\n hasRootSkillFile,\n hasRequestedSkillDir: false,\n })\n ) {\n return { remoteFiles: allFiles, skillFilter: fallbackFilter, isWildcard: false };\n }\n\n return { remoteFiles: filesUnderBase, skillFilter, isWildcard };\n}\n\n/** Base name of an npm package: `@scope/name` -> `name`. */\nfunction npmPackageBaseName(packageName: string): string {\n const slashIndex = packageName.indexOf(\"/\");\n return slashIndex === -1 ? packageName : packageName.substring(slashIndex + 1);\n}\n\n/**\n * Resolve the version to fetch for an npm source: the locked version when\n * available (deterministic re-fetch), otherwise the declared `ref` (exact\n * version or dist-tag, defaulting to \"latest\") resolved via the packument.\n */\nfunction resolveNpmFetchVersion(params: {\n sourceEntry: SourceEntry;\n locked: NpmLockedSource | undefined;\n updateSources: boolean;\n}): { lockedVersion: string | undefined; requestedVersion: string | undefined } {\n const { sourceEntry, locked, updateSources } = params;\n if (locked && !updateSources) {\n return { lockedVersion: locked.resolvedVersion, requestedVersion: locked.requestedVersion };\n }\n return { lockedVersion: undefined, requestedVersion: sourceEntry.ref ?? \"latest\" };\n}\n\n/**\n * Resolve the package version via the registry packument, download the\n * tarball, and verify it against the registry (and, when re-fetching a locked\n * version, the locked) integrity metadata.\n */\nasync function downloadVerifiedNpmTarball(params: {\n packageName: string;\n registryUrl: string;\n token: string | undefined;\n lockedVersion: string | undefined;\n requestedVersion: string | undefined;\n locked: NpmLockedSource | undefined;\n logger: Logger;\n}): Promise<{\n resolvedVersion: string;\n dist: { tarball: string; integrity?: string; shasum?: string };\n tarball: Buffer;\n}> {\n const { packageName, registryUrl, token, lockedVersion, requestedVersion, locked, logger } =\n params;\n\n const packument = await fetchPackument({ registryUrl, packageName, token });\n const resolvedVersion =\n lockedVersion ??\n resolvePackumentVersion({\n packument,\n packageName,\n requested: requestedVersion ?? \"latest\",\n });\n logger.debug(`Resolved ${packageName}@${requestedVersion ?? \"latest\"} to ${resolvedVersion}`);\n\n const dist = getPackumentVersionDist({ packument, packageName, version: resolvedVersion });\n const tarball = await fetchTarball({ tarballUrl: dist.tarball, registryUrl, token });\n const context = `${packageName}@${resolvedVersion}`;\n verifyTarballIntegrity({\n tarball,\n integrity: dist.integrity,\n shasum: dist.shasum,\n context,\n logger,\n });\n // Defense in depth: when re-fetching a locked version, also verify against\n // the integrity recorded at lock time so a registry-side swap is detected.\n if (locked?.integrity && locked.resolvedVersion === resolvedVersion) {\n verifyTarballIntegrity({ tarball, integrity: locked.integrity, context, logger });\n }\n\n return { resolvedVersion, dist, tarball };\n}\n\n/**\n * Extract a verified npm tarball in memory and convert its entries into\n * remote skill files, skipping any file above MAX_FILE_SIZE.\n */\nfunction extractNpmRemoteFiles(params: { tarball: Buffer; logger: Logger }): RemoteSkillFile[] {\n const { tarball, logger } = params;\n const extracted = extractPackageTarball({\n tarball,\n onSkippedEntry: (message) => logger.warn(message),\n });\n const allFiles: RemoteSkillFile[] = [];\n for (const entry of extracted) {\n if (entry.content.length > MAX_FILE_SIZE) {\n logger.warn(\n `Skipping file \"${entry.relativePath}\" (${(entry.content.length / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`,\n );\n continue;\n }\n allFiles.push({ relativePath: entry.relativePath, content: entry.content.toString(\"utf8\") });\n }\n return allFiles;\n}\n\n/** Build the npm lockfile entry for a fetched source. */\nfunction buildNpmLockEntry(params: {\n sourceEntry: SourceEntry;\n requestedVersion: string | undefined;\n resolvedVersion: string;\n dist: { integrity?: string; shasum?: string };\n mergedSkills: Record<string, LockedSkill>;\n}): NpmLockedSource {\n const { sourceEntry, requestedVersion, resolvedVersion, dist, mergedSkills } = params;\n const integrity =\n dist.integrity ?? (dist.shasum !== undefined ? shasumToSri(dist.shasum) : undefined);\n return {\n ...(sourceEntry.registry !== undefined && { registry: sourceEntry.registry }),\n ...(requestedVersion !== undefined && { requestedVersion }),\n resolvedVersion,\n ...(integrity !== undefined && { integrity }),\n resolvedAt: new Date().toISOString(),\n skills: mergedSkills,\n };\n}\n\n/**\n * Fetch skills from a single npm-transport source (EXPERIMENTAL): resolve the\n * package version via the registry packument, download and verify the\n * tarball, extract it in-memory with the hardened tar reader, and install the\n * discovered skills into the curated directory.\n */\nasync function fetchSourceViaNpm(params: {\n sourceEntry: SourceEntry;\n projectRoot: string;\n npmLock: NpmSourcesLock;\n localSkillNames: Set<string>;\n alreadyFetchedSkillNames: Set<string>;\n updateSources: boolean;\n logger: Logger;\n}): Promise<{ skillCount: number; fetchedSkillNames: string[]; updatedLock: NpmSourcesLock }> {\n const {\n sourceEntry,\n projectRoot,\n npmLock,\n localSkillNames,\n alreadyFetchedSkillNames,\n updateSources,\n logger,\n } = params;\n\n const packageName = sourceEntry.source;\n validateNpmPackageName(packageName);\n const registryUrl = sourceEntry.registry ?? DEFAULT_NPM_REGISTRY_URL;\n validateNpmRegistryUrl(registryUrl, { logger });\n const token = resolveNpmToken({ tokenEnv: sourceEntry.tokenEnv });\n\n const sourceKey = packageName;\n const locked = getNpmLockedSource(npmLock, sourceKey);\n const lockedSkillNames = locked ? getNpmLockedSkillNames(locked) : [];\n const curatedDir = join(projectRoot, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);\n\n const { lockedVersion, requestedVersion } = resolveNpmFetchVersion({\n sourceEntry,\n locked,\n updateSources,\n });\n\n // Skip re-fetch if the locked version's curated skills exist on disk\n if (lockedVersion !== undefined) {\n if (await checkLockedSkillsExist(curatedDir, lockedSkillNames)) {\n logger.debug(`Version unchanged for ${sourceKey}, skipping re-fetch.`);\n return { skillCount: 0, fetchedSkillNames: lockedSkillNames, updatedLock: npmLock };\n }\n }\n\n const { resolvedVersion, dist, tarball } = await downloadVerifiedNpmTarball({\n packageName,\n registryUrl,\n token,\n lockedVersion,\n requestedVersion,\n locked,\n logger,\n });\n\n const allFiles = extractNpmRemoteFiles({ tarball, logger });\n\n const declaredFilter = sourceEntry.skills ?? [\"*\"];\n const declaredWildcard = declaredFilter.length === 1 && declaredFilter[0] === \"*\";\n const { remoteFiles, skillFilter, isWildcard } = selectNpmSkillFiles({\n allFiles,\n skillsPath: sourceEntry.path ?? \"skills\",\n skillFilter: declaredFilter,\n isWildcard: declaredWildcard,\n packageName,\n });\n\n const skillFileMap = groupRemoteFilesBySkillRoot({ remoteFiles, skillFilter, isWildcard });\n const allNames = [...skillFileMap.keys()];\n const filteredNames = isWildcard ? allNames : allNames.filter((n) => skillFilter.includes(n));\n\n if (locked) {\n await cleanPreviousCuratedSkills({ curatedDir, lockedSkillNames, logger });\n }\n\n // Adapter so writeSkillAndComputeIntegrity can compare per-skill integrity\n // against the npm lock entry the same way it does for git sources.\n const lockedForIntegrityCheck: LockedSource | undefined = locked\n ? { resolvedRef: locked.resolvedVersion, skills: locked.skills }\n : undefined;\n\n const fetchedSkills: Record<string, LockedSkill> = {};\n for (const skillName of filteredNames) {\n if (\n shouldSkipSkill({\n skillName,\n sourceKey,\n localSkillNames,\n alreadyFetchedSkillNames,\n logger,\n })\n ) {\n continue;\n }\n\n fetchedSkills[skillName] = await writeSkillAndComputeIntegrity({\n skillName,\n files: skillFileMap.get(skillName) ?? [],\n curatedDir,\n locked: lockedForIntegrityCheck,\n resolvedSha: resolvedVersion,\n sourceKey,\n logger,\n });\n logger.debug(`Fetched skill \"${skillName}\" from ${sourceKey}`);\n }\n\n const fetchedNames = Object.keys(fetchedSkills);\n const mergedSkills = mergeFetchedWithLockedSkills({\n fetchedSkills,\n lockedSkills: locked?.skills,\n remoteSkillNames: filteredNames,\n });\n\n const updatedLock = setNpmLockedSource(\n npmLock,\n sourceKey,\n buildNpmLockEntry({ sourceEntry, requestedVersion, resolvedVersion, dist, mergedSkills }),\n );\n\n logger.info(\n `Fetched ${fetchedNames.length} skill(s) from ${sourceKey}: ${fetchedNames.join(\", \") || \"(none)\"}`,\n );\n\n return {\n skillCount: fetchedNames.length,\n fetchedSkillNames: fetchedNames,\n updatedLock,\n };\n}\n","import { ConfigResolver } from \"../../config/config-resolver.js\";\nimport { installApm } from \"../../lib/apm/apm-install.js\";\nimport { apmManifestExists } from \"../../lib/apm/apm-manifest.js\";\nimport { installGh } from \"../../lib/gh/gh-install.js\";\nimport { resolveAndFetchSources } from \"../../lib/sources.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\nexport const INSTALL_MODES = [\"rulesync\", \"apm\", \"gh\"] as const;\nexport type InstallMode = (typeof INSTALL_MODES)[number];\n\nexport type InstallCommandOptions = {\n mode?: InstallMode;\n update?: boolean;\n frozen?: boolean;\n token?: string;\n configPath?: string;\n verbose?: boolean;\n silent?: boolean;\n};\n\nexport async function installCommand(\n logger: Logger,\n options: InstallCommandOptions,\n): Promise<void> {\n const mode: InstallMode = options.mode ?? \"rulesync\";\n\n if (mode === \"gh\") {\n await runGhInstall(logger, options);\n return;\n }\n\n if (mode === \"apm\") {\n await runApmInstall(logger, options);\n return;\n }\n\n await runRulesyncInstall(logger, options);\n}\n\nasync function runRulesyncInstall(logger: Logger, options: InstallCommandOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n // If both apm.yml and rulesync.jsonc sources are defined, refuse to guess.\n // `--mode apm` is required to opt into the APM layout.\n const apmExists = await apmManifestExists(projectRoot);\n\n const config = await ConfigResolver.resolve({\n configPath: options.configPath,\n verbose: options.verbose,\n silent: options.silent,\n });\n const sources = config.getSources();\n\n if (apmExists && sources.length > 0) {\n throw new Error(\n \"Both apm.yml and rulesync.jsonc `sources` are defined. Pass --mode apm or --mode rulesync to disambiguate.\",\n );\n }\n\n if (sources.length === 0) {\n if (apmExists) {\n logger.warn(\n \"No sources defined in rulesync.jsonc, but apm.yml is present. Did you mean --mode apm?\",\n );\n return;\n }\n logger.warn(\"No sources defined in configuration. Nothing to install.\");\n return;\n }\n\n logger.debug(`Installing skills from ${sources.length} source(s)...`);\n\n const result = await resolveAndFetchSources({\n sources,\n projectRoot,\n options: {\n updateSources: options.update,\n frozen: options.frozen,\n token: options.token,\n },\n logger,\n });\n\n if (logger.jsonMode) {\n logger.captureData(\"sourcesProcessed\", result.sourcesProcessed);\n logger.captureData(\"skillsFetched\", result.fetchedSkillCount);\n }\n\n if (result.fetchedSkillCount > 0) {\n logger.success(\n `Installed ${result.fetchedSkillCount} skill(s) from ${result.sourcesProcessed} source(s).`,\n );\n } else {\n logger.success(`All skills up to date (${result.sourcesProcessed} source(s) checked).`);\n }\n}\n\nasync function runApmInstall(logger: Logger, options: InstallCommandOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n if (!(await apmManifestExists(projectRoot))) {\n throw new Error(\n \"--mode apm requires an apm.yml at the project root. Create one or drop --mode apm to fall back to rulesync mode.\",\n );\n }\n\n const result = await installApm({\n projectRoot,\n options: {\n update: options.update,\n frozen: options.frozen,\n token: options.token,\n },\n logger,\n });\n\n if (logger.jsonMode) {\n logger.captureData(\"dependenciesProcessed\", result.dependenciesProcessed);\n logger.captureData(\"deployedFileCount\", result.deployedFileCount);\n logger.captureData(\"failedDependencyCount\", result.failedDependencyCount);\n }\n\n if (result.failedDependencyCount > 0) {\n throw new Error(\n `Failed to install ${result.failedDependencyCount} of ${result.dependenciesProcessed} apm dependency(ies). See the log above for details.`,\n );\n }\n\n if (result.deployedFileCount > 0) {\n logger.success(\n `Installed ${result.deployedFileCount} file(s) from ${result.dependenciesProcessed} apm dependency(ies).`,\n );\n } else {\n logger.success(`All apm dependencies up to date (${result.dependenciesProcessed} checked).`);\n }\n}\n\nasync function runGhInstall(logger: Logger, options: InstallCommandOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n // gh mode reads sources from `rulesync.jsonc`, never from `apm.yml`. The\n // disambiguation between rulesync/apm modes lives in `runRulesyncInstall`;\n // here the user has already opted into gh mode explicitly.\n const config = await ConfigResolver.resolve({\n configPath: options.configPath,\n verbose: options.verbose,\n silent: options.silent,\n });\n const sources = config.getSources();\n\n if (sources.length === 0) {\n logger.warn(\"No sources defined in configuration. Nothing to install.\");\n return;\n }\n\n const result = await installGh({\n projectRoot,\n sources,\n options: {\n update: options.update,\n frozen: options.frozen,\n token: options.token,\n },\n logger,\n });\n\n if (logger.jsonMode) {\n logger.captureData(\"sourcesProcessed\", result.sourcesProcessed);\n logger.captureData(\"installedSkillCount\", result.installedSkillCount);\n logger.captureData(\"failedSourceCount\", result.failedSourceCount);\n }\n\n if (result.failedSourceCount > 0) {\n throw new Error(\n `Failed to install ${result.failedSourceCount} of ${result.sourcesProcessed} gh source(s). See the log above for details.`,\n );\n }\n\n if (result.installedSkillCount > 0) {\n logger.success(\n `Installed ${result.installedSkillCount} skill(s) from ${result.sourcesProcessed} gh source(s).`,\n );\n } else {\n logger.success(`All gh sources up to date (${result.sourcesProcessed} checked).`);\n }\n}\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_CHECKS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncCheck,\n type RulesyncCheckFrontmatter,\n RulesyncCheckFrontmatterSchema,\n} from \"../features/checks/rulesync-check.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxCheckSizeBytes = 1024 * 1024; // 1MB\nconst maxChecksCount = 1000;\n\n/**\n * Tool to list all checks from .rulesync/checks/*.md\n */\nasync function listChecks(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n }>\n> {\n const checksDir = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(checksDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const checks = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n const check = await RulesyncCheck.fromFile({\n relativeFilePath: file,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, file),\n frontmatter: check.getFrontmatter(),\n };\n } catch (error) {\n logger.error(`Failed to read check file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return checks.filter((check): check is NonNullable<typeof check> => check !== null);\n } catch (error) {\n logger.error(\n `Failed to read checks directory (${RULESYNC_CHECKS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific check\n */\nasync function getCheck({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const check = await RulesyncCheck.fromFile({\n relativeFilePath: filename,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n frontmatter: check.getFrontmatter(),\n body: check.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read check file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a check (upsert operation)\n */\nasync function putCheck({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxCheckSizeBytes) {\n throw new Error(\n `Check size ${estimatedSize} bytes exceeds maximum ${maxCheckSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check count constraint\n const existingChecks = await listChecks();\n const isUpdate = existingChecks.some(\n (check) => check.relativePathFromCwd === join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingChecks.length >= maxChecksCount) {\n throw new Error(\n `Maximum number of checks (${maxChecksCount}) reached in ${RULESYNC_CHECKS_RELATIVE_DIR_PATH}`,\n );\n }\n\n const check = new RulesyncCheck({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n validate: true,\n });\n\n // Ensure directory exists\n const checksDir = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH);\n await ensureDir(checksDir);\n\n // Write the file\n await writeFileContent(check.getFilePath(), check.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n frontmatter: check.getFrontmatter(),\n body: check.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write check file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a check\n */\nasync function deleteCheck({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(`Failed to delete check file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Schema for check-related tool parameters\n */\nconst checkToolSchemas = {\n listChecks: z.object({}),\n getCheck: z.object({\n relativePathFromCwd: z.string(),\n }),\n putCheck: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncCheckFrontmatterSchema,\n body: z.string(),\n }),\n deleteCheck: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for check-related operations\n */\nexport const checkTools = {\n listChecks: {\n name: \"listChecks\",\n description: `List all checks from ${join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: checkToolSchemas.listChecks,\n execute: async () => {\n const checks = await listChecks();\n const output = { checks };\n return JSON.stringify(output, null, 2);\n },\n },\n getCheck: {\n name: \"getCheck\",\n description:\n \"Get detailed information about a specific check. relativePathFromCwd parameter is required.\",\n parameters: checkToolSchemas.getCheck,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getCheck({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putCheck: {\n name: \"putCheck\",\n description:\n \"Create or update a check (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: checkToolSchemas.putCheck,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCheckFrontmatter;\n body: string;\n }) => {\n const result = await putCheck({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteCheck: {\n name: \"deleteCheck\",\n description: \"Delete a check file. relativePathFromCwd parameter is required.\",\n parameters: checkToolSchemas.deleteCheck,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteCheck({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_COMMANDS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncCommand,\n type RulesyncCommandFrontmatter,\n RulesyncCommandFrontmatterSchema,\n} from \"../features/commands/rulesync-command.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { stringifyFrontmatter } from \"../utils/frontmatter.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxCommandSizeBytes = 1024 * 1024; // 1MB\nconst maxCommandsCount = 1000;\n\n/**\n * Tool to list all commands from .rulesync/commands/*.md\n */\nasync function listCommands(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n }>\n> {\n const commandsDir = join(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(commandsDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const commands = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n checkPathTraversal({\n relativePath: file,\n intendedRootDir: commandsDir,\n });\n\n const command = await RulesyncCommand.fromFile({\n relativeFilePath: file,\n });\n\n const frontmatter = command.getFrontmatter();\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read command file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return commands.filter((command): command is NonNullable<typeof command> => command !== null);\n } catch (error) {\n logger.error(\n `Failed to read commands directory (${RULESYNC_COMMANDS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific command\n */\nasync function getCommand({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const command = await RulesyncCommand.fromFile({\n relativeFilePath: filename,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n frontmatter: command.getFrontmatter(),\n body: command.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read command file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a command (upsert operation)\n */\nasync function putCommand({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxCommandSizeBytes) {\n throw new Error(\n `Command size ${estimatedSize} bytes exceeds maximum ${maxCommandSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check command count constraint\n const existingCommands = await listCommands();\n const isUpdate = existingCommands.some(\n (command) =>\n command.relativePathFromCwd === join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingCommands.length >= maxCommandsCount) {\n throw new Error(\n `Maximum number of commands (${maxCommandsCount}) reached in ${RULESYNC_COMMANDS_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Create a new RulesyncCommand instance\n const fileContent = stringifyFrontmatter(body, frontmatter);\n const command = new RulesyncCommand({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_COMMANDS_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n fileContent,\n validate: true,\n });\n\n // Ensure directory exists\n const commandsDir = join(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);\n await ensureDir(commandsDir);\n\n // Write the file\n await writeFileContent(command.getFilePath(), command.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n frontmatter: command.getFrontmatter(),\n body: command.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write command file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a command\n */\nasync function deleteCommand({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Schema for command-related tool parameters\n */\nconst commandToolSchemas = {\n listCommands: z.object({}),\n getCommand: z.object({\n relativePathFromCwd: z.string(),\n }),\n putCommand: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncCommandFrontmatterSchema,\n body: z.string(),\n }),\n deleteCommand: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for command-related operations\n */\nexport const commandTools = {\n listCommands: {\n name: \"listCommands\",\n description: `List all commands from ${join(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: commandToolSchemas.listCommands,\n execute: async () => {\n const commands = await listCommands();\n const output = { commands };\n return JSON.stringify(output, null, 2);\n },\n },\n getCommand: {\n name: \"getCommand\",\n description:\n \"Get detailed information about a specific command. relativePathFromCwd parameter is required.\",\n parameters: commandToolSchemas.getCommand,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getCommand({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putCommand: {\n name: \"putCommand\",\n description:\n \"Create or update a command (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: commandToolSchemas.putCommand,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncCommandFrontmatter;\n body: string;\n }) => {\n const result = await putCommand({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteCommand: {\n name: \"deleteCommand\",\n description: \"Delete a command file. relativePathFromCwd parameter is required.\",\n parameters: commandToolSchemas.deleteCommand,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteCommand({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { z } from \"zod/mini\";\n\nimport { ConfigResolver } from \"../config/config-resolver.js\";\nimport { Config } from \"../config/config.js\";\nimport { convertFromTool, type ConvertResult } from \"../lib/convert.js\";\nimport { type RulesyncFeatures } from \"../types/features.js\";\nimport { ALL_TOOL_TARGETS, type ToolTarget, ToolTargetSchema } from \"../types/tool-targets.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\nimport { calculateTotalCount } from \"../utils/result.js\";\nimport { type McpResultCounts } from \"./types.js\";\n\n/**\n * Schema for convert options\n * Excluded parameters:\n * - outputRoots: Always use [process.cwd()] in MCP context\n * - verbose: Meaningless in MCP (no console output)\n * - silent: Meaningless in MCP\n * - configPath: Always use default path from process.cwd()\n */\nexport const convertOptionsSchema = z.object({\n from: z.string(),\n to: z.array(z.string()),\n features: z.optional(z.array(z.string())),\n global: z.optional(z.boolean()),\n dryRun: z.optional(z.boolean()),\n});\n\nexport type ConvertOptions = z.infer<typeof convertOptionsSchema>;\n\nexport type McpConvertResult = {\n success: boolean;\n result?: McpResultCounts;\n config?: {\n from: string;\n to: string[];\n features: string[];\n global: boolean;\n dryRun: boolean;\n };\n error?: string;\n};\n\nfunction parseToolTarget(value: string, label: string): ToolTarget {\n const result = ToolTargetSchema.safeParse(value);\n if (!result.success) {\n throw new Error(\n `Invalid ${label} tool '${value}'. Must be one of: ${ALL_TOOL_TARGETS.join(\", \")}`,\n );\n }\n return result.data;\n}\n\n/**\n * Execute the rulesync convert command via MCP\n * Configuration priority: MCP Parameters > rulesync.local.jsonc > rulesync.jsonc > Default values\n */\nexport async function executeConvert(options: ConvertOptions): Promise<McpConvertResult> {\n try {\n // Validate from\n if (!options.from) {\n return {\n success: false,\n error: \"from is required. Please specify a source tool to convert from.\",\n };\n }\n\n // Validate to\n if (!options.to || options.to.length === 0) {\n return {\n success: false,\n error: \"to is required and must not be empty. Please specify destination tools.\",\n };\n }\n\n const fromTool = parseToolTarget(options.from, \"source\");\n const toToolsRaw = options.to.map((t) => parseToolTarget(t, \"destination\"));\n const toTools = Array.from(new Set(toToolsRaw));\n\n if (toTools.includes(fromTool)) {\n return {\n success: false,\n error:\n `Destination tools must not include the source tool '${fromTool}'. ` +\n `Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`,\n };\n }\n\n // Resolve config with MCP parameters taking precedence\n // ConfigResolver handles: CLI options > rulesync.local.jsonc > rulesync.jsonc > defaults\n // In MCP context, options act as CLI options (highest priority)\n // Pass both source and destinations as `targets` so per-target feature maps\n // in `rulesync.jsonc` are honored for every tool involved. Default features\n // to `*` so every feature that both tools support is attempted.\n const config = await ConfigResolver.resolve({\n targets: [fromTool, ...toTools],\n features: (options.features ?? [\"*\"]) as RulesyncFeatures,\n global: options.global,\n dryRun: options.dryRun,\n // Always use default outputRoots (process.cwd()) and configPath\n // verbose and silent are meaningless in MCP context\n verbose: false,\n silent: true,\n });\n\n const logger = new ConsoleLogger({ verbose: false, silent: true });\n const convertResult = await convertFromTool({ config, fromTool, toTools, logger });\n\n return buildSuccessResponse({ convertResult, config, fromTool, toTools });\n } catch (error) {\n return {\n success: false,\n error: formatError(error),\n };\n }\n}\n\nfunction buildSuccessResponse(params: {\n convertResult: ConvertResult;\n config: Config;\n fromTool: ToolTarget;\n toTools: ToolTarget[];\n}): McpConvertResult {\n const { convertResult, config, fromTool, toTools } = params;\n\n const totalCount = calculateTotalCount(convertResult);\n\n return {\n success: true,\n result: {\n rulesCount: convertResult.rulesCount,\n ignoreCount: convertResult.ignoreCount,\n mcpCount: convertResult.mcpCount,\n commandsCount: convertResult.commandsCount,\n subagentsCount: convertResult.subagentsCount,\n skillsCount: convertResult.skillsCount,\n hooksCount: convertResult.hooksCount,\n permissionsCount: convertResult.permissionsCount,\n checksCount: convertResult.checksCount,\n totalCount,\n },\n config: {\n from: fromTool,\n to: toTools,\n features: config.getFeatures(),\n global: config.getGlobal(),\n dryRun: config.isPreviewMode(),\n },\n };\n}\n\nconst convertToolSchemas = {\n executeConvert: convertOptionsSchema,\n};\n\nexport const convertTools = {\n executeConvert: {\n name: \"executeConvert\",\n description:\n \"Execute the rulesync convert command to convert configuration files between AI tools without writing intermediate .rulesync/ files. Requires a source tool (from) and one or more destination tools (to).\",\n parameters: convertToolSchemas.executeConvert,\n execute: async (options: ConvertOptions): Promise<string> => {\n const result = await executeConvert(options);\n return JSON.stringify(result, null, 2);\n },\n },\n};\n","import { z } from \"zod/mini\";\n\nimport { ConfigResolver } from \"../config/config-resolver.js\";\nimport { Config } from \"../config/config.js\";\nimport { checkRulesyncDirExists, generate, type GenerateResult } from \"../lib/generate.js\";\nimport { type RulesyncFeatures } from \"../types/features.js\";\nimport { type RulesyncTargets } from \"../types/tool-targets.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\nimport { calculateTotalCount } from \"../utils/result.js\";\nimport { type McpResultCounts } from \"./types.js\";\n\n/**\n * Schema for generate options\n * Excluded parameters:\n * - outputRoots: Always use [process.cwd()] in MCP context\n * - verbose: Meaningless in MCP (no console output)\n * - silent: Meaningless in MCP\n * - configPath: Always use default path from process.cwd()\n */\nexport const generateOptionsSchema = z.object({\n targets: z.optional(z.array(z.string())),\n features: z.optional(z.array(z.string())),\n delete: z.optional(z.boolean()),\n global: z.optional(z.boolean()),\n simulateCommands: z.optional(z.boolean()),\n simulateSubagents: z.optional(z.boolean()),\n simulateSkills: z.optional(z.boolean()),\n});\n\nexport type GenerateOptions = z.infer<typeof generateOptionsSchema>;\n\nexport type McpGenerateResult = {\n success: boolean;\n /**\n * Human-readable summary of the outcome. Clarifies that a `totalCount` of 0\n * means \"already up to date\" (success with nothing to write) rather than a\n * failure, since `generate` is idempotent and only writes changed files.\n */\n message?: string;\n result?: McpResultCounts;\n config?: {\n targets: string[];\n features: string[];\n global: boolean;\n delete: boolean;\n simulateCommands: boolean;\n simulateSubagents: boolean;\n simulateSkills: boolean;\n };\n error?: string;\n};\n\n/**\n * Execute the rulesync generate command via MCP\n * Configuration priority: MCP Parameters > rulesync.local.jsonc > rulesync.jsonc > Default values\n */\nexport async function executeGenerate(options: GenerateOptions = {}): Promise<McpGenerateResult> {\n try {\n // Check if .rulesync directory exists\n const exists = await checkRulesyncDirExists({ inputRoot: process.cwd() });\n if (!exists) {\n return {\n success: false,\n error:\n \".rulesync directory does not exist. Please run 'rulesync init' first or create the directory manually.\",\n };\n }\n\n // Resolve config with MCP parameters taking precedence\n // ConfigResolver handles: CLI options > rulesync.local.jsonc > rulesync.jsonc > defaults\n // In MCP context, options act as CLI options (highest priority)\n const config = await ConfigResolver.resolve({\n targets: options.targets as RulesyncTargets | undefined,\n features: options.features as RulesyncFeatures | undefined,\n delete: options.delete,\n global: options.global,\n simulateCommands: options.simulateCommands,\n simulateSubagents: options.simulateSubagents,\n simulateSkills: options.simulateSkills,\n // Always use default outputRoots (process.cwd()) and configPath\n // verbose and silent are meaningless in MCP context\n verbose: false,\n silent: true,\n });\n\n const logger = new ConsoleLogger({ verbose: false, silent: true });\n const generateResult = await generate({ config, logger });\n\n return buildSuccessResponse({ generateResult, config });\n } catch (error) {\n return {\n success: false,\n error: formatError(error),\n };\n }\n}\n\n/**\n * Build a human-readable summary of a successful generation.\n *\n * `generate` is idempotent: `totalCount` reflects only files whose content\n * actually changed on disk, so a count of 0 is a normal \"nothing to update\"\n * outcome — not a failure. The message makes that explicit so MCP callers do\n * not misread a zero count as a broken generate.\n */\nfunction buildGenerateMessage(params: { totalCount: number; config: Config }): string {\n const { totalCount, config } = params;\n const targets = config.getTargets().join(\", \");\n const features = config.getFeatures().join(\", \");\n\n if (totalCount > 0) {\n return `Generated ${totalCount} file(s) for targets [${targets}] and features [${features}].`;\n }\n\n return (\n `No files needed updating for targets [${targets}] and features [${features}]. ` +\n `'generate' only writes files whose content changed, so a totalCount of 0 means the ` +\n `outputs are already up to date — this is a successful no-op, not a failure.`\n );\n}\n\nfunction buildSuccessResponse(params: {\n generateResult: GenerateResult;\n config: Config;\n}): McpGenerateResult {\n const { generateResult, config } = params;\n\n const totalCount = calculateTotalCount(generateResult);\n\n return {\n success: true,\n message: buildGenerateMessage({ totalCount, config }),\n result: {\n rulesCount: generateResult.rulesCount,\n ignoreCount: generateResult.ignoreCount,\n mcpCount: generateResult.mcpCount,\n commandsCount: generateResult.commandsCount,\n subagentsCount: generateResult.subagentsCount,\n skillsCount: generateResult.skillsCount,\n hooksCount: generateResult.hooksCount,\n permissionsCount: generateResult.permissionsCount,\n checksCount: generateResult.checksCount,\n totalCount,\n },\n config: {\n targets: config.getTargets(),\n features: config.getFeatures(),\n global: config.getGlobal(),\n delete: config.getDelete(),\n simulateCommands: config.getSimulateCommands(),\n simulateSubagents: config.getSimulateSubagents(),\n simulateSkills: config.getSimulateSkills(),\n },\n };\n}\n\nconst generateToolSchemas = {\n executeGenerate: generateOptionsSchema,\n};\n\nexport const generateTools = {\n executeGenerate: {\n name: \"executeGenerate\",\n description:\n \"Execute the rulesync generate command to create output files for AI tools. Uses rulesync.jsonc settings by default, but options can override them. Idempotent: only files whose content changed are written, so a totalCount of 0 means the outputs are already up to date (a successful no-op), not a failure. See the 'message' field for a human-readable summary.\",\n parameters: generateToolSchemas.executeGenerate,\n execute: async (options: GenerateOptions = {}): Promise<string> => {\n const result = await executeGenerate(options);\n return JSON.stringify(result, null, 2);\n },\n },\n};\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_HOOKS_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { RulesyncHooks } from \"../features/hooks/rulesync-hooks.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, fileExists, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxHooksSizeBytes = 1024 * 1024; // 1MB\n\n/**\n * Tool to get the hooks configuration file\n */\nasync function getHooksFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n try {\n const rulesyncHooks = await RulesyncHooks.fromFile({\n validate: true,\n });\n\n const relativePathFromCwd = join(\n rulesyncHooks.getRelativeDirPath(),\n rulesyncHooks.getRelativeFilePath(),\n );\n\n return {\n relativePathFromCwd,\n content: rulesyncHooks.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to read hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the hooks configuration file (upsert operation)\n */\nasync function putHooksFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n // Check file size constraint\n if (content.length > maxHooksSizeBytes) {\n throw new Error(\n `Hooks file size ${content.length} bytes exceeds maximum ${maxHooksSizeBytes} bytes (1MB) for ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}`,\n );\n }\n\n // Validate JSON format\n try {\n JSON.parse(content);\n } catch (error) {\n throw new Error(\n `Invalid JSON format in hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncHooks.getSettablePaths();\n\n // A .jsonc variant takes precedence at read time, so writing the .json\n // variant while it exists would be silently ignored — and rewriting the\n // .jsonc file here would destroy its comments. Refuse instead.\n const jsoncRelativePath = join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);\n if (await fileExists(join(outputRoot, jsoncRelativePath))) {\n throw new Error(\n `${jsoncRelativePath} exists and takes precedence over ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}. Edit ${jsoncRelativePath} directly instead.`,\n );\n }\n\n const relativeDirPath = paths.relativeDirPath;\n const relativeFilePath = paths.relativeFilePath;\n const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);\n\n // Create a RulesyncHooks instance to validate the content\n const rulesyncHooks = new RulesyncHooks({\n outputRoot,\n relativeDirPath,\n relativeFilePath,\n fileContent: content,\n validate: true,\n });\n\n // Ensure directory exists\n await ensureDir(join(outputRoot, relativeDirPath));\n\n // Write the file\n await writeFileContent(fullPath, content);\n\n const relativePathFromCwd = join(relativeDirPath, relativeFilePath);\n\n return {\n relativePathFromCwd,\n content: rulesyncHooks.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to write hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the hooks configuration file\n */\nasync function deleteHooksFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncHooks.getSettablePaths();\n\n const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);\n\n await removeFile(filePath);\n\n // Remove the .jsonc variant if it exists\n await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));\n\n const relativePathFromCwd = join(paths.relativeDirPath, paths.relativeFilePath);\n\n return {\n relativePathFromCwd,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for hooks-related tool parameters\n */\nconst hooksToolSchemas = {\n getHooksFile: z.object({}),\n putHooksFile: z.object({\n content: z.string(),\n }),\n deleteHooksFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for hooks-related operations\n */\nexport const hooksTools = {\n getHooksFile: {\n name: \"getHooksFile\",\n description: `Get the hooks configuration file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}).`,\n parameters: hooksToolSchemas.getHooksFile,\n execute: async () => {\n const result = await getHooksFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putHooksFile: {\n name: \"putHooksFile\",\n description:\n \"Create or update the hooks configuration file (upsert operation). content parameter is required and must be valid JSON.\",\n parameters: hooksToolSchemas.putHooksFile,\n execute: async (args: { content: string }) => {\n const result = await putHooksFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteHooksFile: {\n name: \"deleteHooksFile\",\n description: \"Delete the hooks configuration file.\",\n parameters: hooksToolSchemas.deleteHooksFile,\n execute: async () => {\n const result = await deleteHooksFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport {\n RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n RULESYNC_IGNORE_RELATIVE_FILE_PATH,\n} from \"../constants/rulesync-paths.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, readFileContent, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxIgnoreFileSizeBytes = 100 * 1024; // 100KB\n\n/**\n * Tool to get the content of .rulesync/.aiignore file\n */\nasync function getIgnoreFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n const ignoreFilePath = join(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);\n\n try {\n const content = await readFileContent(ignoreFilePath);\n\n return {\n relativePathFromCwd: RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n content,\n };\n } catch (error) {\n throw new Error(\n `Failed to read ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the .rulesync/.aiignore file (upsert operation)\n */\nasync function putIgnoreFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n const ignoreFilePath = join(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);\n\n // Check file size constraint\n const contentSizeBytes = Buffer.byteLength(content, \"utf8\");\n if (contentSizeBytes > maxIgnoreFileSizeBytes) {\n throw new Error(\n `Ignore file size ${contentSizeBytes} bytes exceeds maximum ${maxIgnoreFileSizeBytes} bytes (100KB) for ${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}`,\n );\n }\n\n try {\n // Ensure parent directory exists (should be cwd, but just to be safe)\n await ensureDir(process.cwd());\n\n // Write the file\n await writeFileContent(ignoreFilePath, content);\n\n return {\n relativePathFromCwd: RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n content,\n };\n } catch (error) {\n throw new Error(\n `Failed to write ignore file (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the .rulesyncignore (legacy) and .rulesync/.aiignore (recommended) files\n */\nasync function deleteIgnoreFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n const aiignorePath = join(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);\n const legacyIgnorePath = join(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);\n\n try {\n // Attempt to remove both files. The removeFile helper is expected to be idempotent\n // (no-throw for non-existent files). If any real IO error happens, the Promise.all\n // will reject and we propagate an error.\n await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);\n\n return {\n // Keep the historical return shape — point to the recommended file path\n // for backward compatibility.\n relativePathFromCwd: RULESYNC_AIIGNORE_RELATIVE_FILE_PATH,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete ignore files (${RULESYNC_AIIGNORE_RELATIVE_FILE_PATH}, ${RULESYNC_IGNORE_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for ignore-related tool parameters\n */\nconst ignoreToolSchemas = {\n getIgnoreFile: z.object({}),\n putIgnoreFile: z.object({\n content: z.string(),\n }),\n deleteIgnoreFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for ignore-related operations\n */\nexport const ignoreTools = {\n getIgnoreFile: {\n name: \"getIgnoreFile\",\n description: \"Get the content of the .rulesyncignore file from the project root.\",\n parameters: ignoreToolSchemas.getIgnoreFile,\n execute: async () => {\n const result = await getIgnoreFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putIgnoreFile: {\n name: \"putIgnoreFile\",\n description:\n \"Create or update the .rulesync/.aiignore file (upsert operation). content parameter is required.\",\n parameters: ignoreToolSchemas.putIgnoreFile,\n execute: async (args: { content: string }) => {\n const result = await putIgnoreFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteIgnoreFile: {\n name: \"deleteIgnoreFile\",\n description: \"Delete the .rulesyncignore and .rulesync/.aiignore files.\",\n parameters: ignoreToolSchemas.deleteIgnoreFile,\n execute: async () => {\n const result = await deleteIgnoreFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { z } from \"zod/mini\";\n\nimport { ConfigResolver } from \"../config/config-resolver.js\";\nimport { Config } from \"../config/config.js\";\nimport { importFromTool, type ImportResult } from \"../lib/import.js\";\nimport { type RulesyncFeatures } from \"../types/features.js\";\nimport { type RulesyncTargets, type ToolTarget } from \"../types/tool-targets.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\nimport { calculateTotalCount } from \"../utils/result.js\";\nimport { type McpResultCounts } from \"./types.js\";\n\n/**\n * Schema for import options\n * Note: Import requires exactly one target tool\n * Excluded parameters:\n * - outputRoots: Always use [process.cwd()] in MCP context\n * - verbose: Meaningless in MCP (no console output)\n * - silent: Meaningless in MCP\n * - configPath: Always use default path from process.cwd()\n * - delete: Not applicable to import\n * - simulateCommands/simulateSubagents/simulateSkills: Not applicable to import\n */\nexport const importOptionsSchema = z.object({\n target: z.string(),\n features: z.optional(z.array(z.string())),\n global: z.optional(z.boolean()),\n});\n\nexport type ImportOptions = z.infer<typeof importOptionsSchema>;\n\nexport type McpImportResult = {\n success: boolean;\n result?: McpResultCounts;\n config?: {\n target: string;\n features: string[];\n global: boolean;\n };\n error?: string;\n};\n\n/**\n * Execute the rulesync import command via MCP\n * Configuration priority: MCP Parameters > rulesync.local.jsonc > rulesync.jsonc > Default values\n */\nexport async function executeImport(options: ImportOptions): Promise<McpImportResult> {\n try {\n // Validate target\n if (!options.target) {\n return {\n success: false,\n error: \"target is required. Please specify a tool to import from.\",\n };\n }\n\n // Resolve config with MCP parameters taking precedence\n // ConfigResolver handles: CLI options > rulesync.local.jsonc > rulesync.jsonc > defaults\n // In MCP context, options act as CLI options (highest priority)\n const config = await ConfigResolver.resolve({\n targets: [options.target] as RulesyncTargets,\n features: options.features as RulesyncFeatures | undefined,\n global: options.global,\n // Always use default outputRoots (process.cwd()) and configPath\n // verbose and silent are meaningless in MCP context\n verbose: false,\n silent: true,\n });\n\n const tool = config.getTargets()[0] as ToolTarget;\n\n const logger = new ConsoleLogger({ verbose: false, silent: true });\n const importResult = await importFromTool({ config, tool, logger });\n\n return buildSuccessResponse({ importResult, config, tool });\n } catch (error) {\n return {\n success: false,\n error: formatError(error),\n };\n }\n}\n\nfunction buildSuccessResponse(params: {\n importResult: ImportResult;\n config: Config;\n tool: ToolTarget;\n}): McpImportResult {\n const { importResult, config, tool } = params;\n\n const totalCount = calculateTotalCount(importResult);\n\n return {\n success: true,\n result: {\n rulesCount: importResult.rulesCount,\n ignoreCount: importResult.ignoreCount,\n mcpCount: importResult.mcpCount,\n commandsCount: importResult.commandsCount,\n subagentsCount: importResult.subagentsCount,\n skillsCount: importResult.skillsCount,\n hooksCount: importResult.hooksCount,\n permissionsCount: importResult.permissionsCount,\n checksCount: importResult.checksCount,\n totalCount,\n },\n config: {\n target: tool,\n features: config.getFeatures(),\n global: config.getGlobal(),\n },\n };\n}\n\nconst importToolSchemas = {\n executeImport: importOptionsSchema,\n};\n\nexport const importTools = {\n executeImport: {\n name: \"executeImport\",\n description:\n \"Execute the rulesync import command to import configuration files from an AI tool into .rulesync directory. Requires exactly one target tool to import from.\",\n parameters: importToolSchemas.executeImport,\n execute: async (options: ImportOptions): Promise<string> => {\n const result = await executeImport(options);\n return JSON.stringify(result, null, 2);\n },\n },\n};\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_MCP_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { RulesyncMcp } from \"../features/mcp/rulesync-mcp.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, fileExists, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxMcpSizeBytes = 1024 * 1024; // 1MB\n\n/**\n * Tool to get the MCP configuration file\n */\nasync function getMcpFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n try {\n const rulesyncMcp = await RulesyncMcp.fromFile({\n validate: true,\n });\n\n const relativePathFromCwd = join(\n rulesyncMcp.getRelativeDirPath(),\n rulesyncMcp.getRelativeFilePath(),\n );\n\n return {\n relativePathFromCwd,\n content: rulesyncMcp.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to read MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the MCP configuration file (upsert operation)\n */\nasync function putMcpFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n // Check file size constraint\n if (content.length > maxMcpSizeBytes) {\n throw new Error(\n `MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB) for ${RULESYNC_MCP_RELATIVE_FILE_PATH}`,\n );\n }\n\n // Validate JSON format\n try {\n JSON.parse(content);\n } catch (error) {\n throw new Error(\n `Invalid JSON format in MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncMcp.getSettablePaths();\n\n // A .jsonc variant takes precedence at read time, so writing the .json\n // variant while it exists would be silently ignored — and rewriting the\n // .jsonc file here would destroy its comments. Refuse instead.\n const jsoncRelativePath = join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);\n if (await fileExists(join(outputRoot, jsoncRelativePath))) {\n throw new Error(\n `${jsoncRelativePath} exists and takes precedence over ${RULESYNC_MCP_RELATIVE_FILE_PATH}. Edit ${jsoncRelativePath} directly instead.`,\n );\n }\n\n // Use recommended path\n const relativeDirPath = paths.recommended.relativeDirPath;\n const relativeFilePath = paths.recommended.relativeFilePath;\n const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);\n\n // Create a RulesyncMcp instance to validate the content\n const rulesyncMcp = new RulesyncMcp({\n outputRoot,\n relativeDirPath,\n relativeFilePath,\n fileContent: content,\n validate: true,\n });\n\n // Ensure directory exists\n await ensureDir(join(outputRoot, relativeDirPath));\n\n // Write the file\n await writeFileContent(fullPath, content);\n\n const relativePathFromCwd = join(relativeDirPath, relativeFilePath);\n\n return {\n relativePathFromCwd,\n content: rulesyncMcp.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to write MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the MCP configuration file\n */\nasync function deleteMcpFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncMcp.getSettablePaths();\n\n // Try to delete both recommended and legacy paths\n const recommendedPath = join(\n outputRoot,\n paths.recommended.relativeDirPath,\n paths.recommended.relativeFilePath,\n );\n const legacyPath = join(\n outputRoot,\n paths.legacy.relativeDirPath,\n paths.legacy.relativeFilePath,\n );\n\n // Remove recommended path if it exists\n await removeFile(recommendedPath);\n\n // Remove the .jsonc variant if it exists\n await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));\n\n // Remove legacy path if it exists\n await removeFile(legacyPath);\n\n const relativePathFromCwd = join(\n paths.recommended.relativeDirPath,\n paths.recommended.relativeFilePath,\n );\n\n return {\n relativePathFromCwd,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for MCP-related tool parameters\n */\nconst mcpToolSchemas = {\n getMcpFile: z.object({}),\n putMcpFile: z.object({\n content: z.string(),\n }),\n deleteMcpFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for MCP-related operations\n */\nexport const mcpTools = {\n getMcpFile: {\n name: \"getMcpFile\",\n description: `Get the MCP configuration file (${RULESYNC_MCP_RELATIVE_FILE_PATH}).`,\n parameters: mcpToolSchemas.getMcpFile,\n execute: async () => {\n const result = await getMcpFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putMcpFile: {\n name: \"putMcpFile\",\n description:\n \"Create or update the MCP configuration file (upsert operation). content parameter is required and must be valid JSON.\",\n parameters: mcpToolSchemas.putMcpFile,\n execute: async (args: { content: string }) => {\n const result = await putMcpFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteMcpFile: {\n name: \"deleteMcpFile\",\n description: \"Delete the MCP configuration file.\",\n parameters: mcpToolSchemas.deleteMcpFile,\n execute: async () => {\n const result = await deleteMcpFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH } from \"../constants/rulesync-paths.js\";\nimport { RulesyncPermissions } from \"../features/permissions/rulesync-permissions.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ensureDir, fileExists, removeFile, writeFileContent } from \"../utils/file.js\";\n\nconst maxPermissionsSizeBytes = 1024 * 1024; // 1MB\n\n/**\n * Tool to get the permissions configuration file\n */\nasync function getPermissionsFile(): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n try {\n const rulesyncPermissions = await RulesyncPermissions.fromFile({\n validate: true,\n });\n\n const relativePathFromCwd = join(\n rulesyncPermissions.getRelativeDirPath(),\n rulesyncPermissions.getRelativeFilePath(),\n );\n\n return {\n relativePathFromCwd,\n content: rulesyncPermissions.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to read permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update the permissions configuration file (upsert operation)\n */\nasync function putPermissionsFile({ content }: { content: string }): Promise<{\n relativePathFromCwd: string;\n content: string;\n}> {\n // Check file size constraint\n if (content.length > maxPermissionsSizeBytes) {\n throw new Error(\n `Permissions file size ${content.length} bytes exceeds maximum ${maxPermissionsSizeBytes} bytes (1MB) for ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}`,\n );\n }\n\n // Validate JSON format\n try {\n JSON.parse(content);\n } catch (error) {\n throw new Error(\n `Invalid JSON format in permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncPermissions.getSettablePaths();\n\n // A .jsonc variant takes precedence at read time, so writing the .json\n // variant while it exists would be silently ignored — and rewriting the\n // .jsonc file here would destroy its comments. Refuse instead.\n const jsoncRelativePath = join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);\n if (await fileExists(join(outputRoot, jsoncRelativePath))) {\n throw new Error(\n `${jsoncRelativePath} exists and takes precedence over ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}. Edit ${jsoncRelativePath} directly instead.`,\n );\n }\n\n const relativeDirPath = paths.relativeDirPath;\n const relativeFilePath = paths.relativeFilePath;\n const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);\n\n // Create a RulesyncPermissions instance to validate the content\n const rulesyncPermissions = new RulesyncPermissions({\n outputRoot,\n relativeDirPath,\n relativeFilePath,\n fileContent: content,\n validate: true,\n });\n\n // Ensure directory exists\n await ensureDir(join(outputRoot, relativeDirPath));\n\n // Write the file\n await writeFileContent(fullPath, content);\n\n const relativePathFromCwd = join(relativeDirPath, relativeFilePath);\n\n return {\n relativePathFromCwd,\n content: rulesyncPermissions.getFileContent(),\n };\n } catch (error) {\n throw new Error(\n `Failed to write permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete the permissions configuration file\n */\nasync function deletePermissionsFile(): Promise<{\n relativePathFromCwd: string;\n}> {\n try {\n const outputRoot = process.cwd();\n const paths = RulesyncPermissions.getSettablePaths();\n\n const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);\n\n await removeFile(filePath);\n\n // Remove the .jsonc variant if it exists\n await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));\n\n const relativePathFromCwd = join(paths.relativeDirPath, paths.relativeFilePath);\n\n return {\n relativePathFromCwd,\n };\n } catch (error) {\n throw new Error(\n `Failed to delete permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for permissions-related tool parameters\n */\nconst permissionsToolSchemas = {\n getPermissionsFile: z.object({}),\n putPermissionsFile: z.object({\n content: z.string(),\n }),\n deletePermissionsFile: z.object({}),\n} as const;\n\n/**\n * Tool definitions for permissions-related operations\n */\nexport const permissionsTools = {\n getPermissionsFile: {\n name: \"getPermissionsFile\",\n description: `Get the permissions configuration file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}).`,\n parameters: permissionsToolSchemas.getPermissionsFile,\n execute: async () => {\n const result = await getPermissionsFile();\n return JSON.stringify(result, null, 2);\n },\n },\n putPermissionsFile: {\n name: \"putPermissionsFile\",\n description:\n \"Create or update the permissions configuration file (upsert operation). content parameter is required and must be valid JSON.\",\n parameters: permissionsToolSchemas.putPermissionsFile,\n execute: async (args: { content: string }) => {\n const result = await putPermissionsFile({ content: args.content });\n return JSON.stringify(result, null, 2);\n },\n },\n deletePermissionsFile: {\n name: \"deletePermissionsFile\",\n description: \"Delete the permissions configuration file.\",\n parameters: permissionsToolSchemas.deletePermissionsFile,\n execute: async () => {\n const result = await deletePermissionsFile();\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_RULES_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncRule,\n type RulesyncRuleFrontmatter,\n type RulesyncRuleFrontmatterInput,\n RulesyncRuleFrontmatterSchema,\n} from \"../features/rules/rulesync-rule.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxRuleSizeBytes = 1024 * 1024; // 1MB\nconst maxRulesCount = 1000;\n\n/**\n * Tool to list all rules from .rulesync/rules/*.md\n */\nasync function listRules(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatter;\n }>\n> {\n const rulesDir = join(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(rulesDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const rules = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n // Read the rule file using RulesyncRule\n const rule = await RulesyncRule.fromFile({\n relativeFilePath: file,\n validate: true,\n });\n\n const frontmatter = rule.getFrontmatter();\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, file),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read rule file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return rules.filter((rule): rule is NonNullable<typeof rule> => rule !== null);\n } catch (error) {\n logger.error(\n `Failed to read rules directory (${RULESYNC_RULES_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific rule\n */\nasync function getRule({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const rule = await RulesyncRule.fromFile({\n relativeFilePath: filename,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n frontmatter: rule.getFrontmatter(),\n body: rule.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read rule file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a rule (upsert operation)\n */\nasync function putRule({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatterInput;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxRuleSizeBytes) {\n throw new Error(\n `Rule size ${estimatedSize} bytes exceeds maximum ${maxRuleSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check rule count constraint\n const existingRules = await listRules();\n const isUpdate = existingRules.some(\n (rule) => rule.relativePathFromCwd === join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingRules.length >= maxRulesCount) {\n throw new Error(\n `Maximum number of rules (${maxRulesCount}) reached in ${RULESYNC_RULES_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Create a new RulesyncRule instance\n const rule = new RulesyncRule({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n validate: true,\n });\n\n // Ensure directory exists\n const rulesDir = join(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);\n await ensureDir(rulesDir);\n\n // Write the file\n await writeFileContent(rule.getFilePath(), rule.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n frontmatter: rule.getFrontmatter(),\n body: rule.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write rule file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a rule\n */\nasync function deleteRule({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Schema for rule-related tool parameters\n */\nconst ruleToolSchemas = {\n listRules: z.object({}),\n getRule: z.object({\n relativePathFromCwd: z.string(),\n }),\n putRule: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncRuleFrontmatterSchema,\n body: z.string(),\n }),\n deleteRule: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for rule-related operations\n */\nexport const ruleTools = {\n listRules: {\n name: \"listRules\",\n description: `List all rules from ${join(RULESYNC_RULES_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: ruleToolSchemas.listRules,\n execute: async () => {\n const rules = await listRules();\n const output = { rules };\n return JSON.stringify(output, null, 2);\n },\n },\n getRule: {\n name: \"getRule\",\n description:\n \"Get detailed information about a specific rule. relativePathFromCwd parameter is required.\",\n parameters: ruleToolSchemas.getRule,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getRule({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putRule: {\n name: \"putRule\",\n description:\n \"Create or update a rule (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: ruleToolSchemas.putRule,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncRuleFrontmatterInput;\n body: string;\n }) => {\n const result = await putRule({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteRule: {\n name: \"deleteRule\",\n description: \"Delete a rule file. relativePathFromCwd parameter is required.\",\n parameters: ruleToolSchemas.deleteRule,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteRule({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, dirname, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { SKILL_FILE_NAME } from \"../constants/general.js\";\nimport { RULESYNC_SKILLS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncSkill,\n type RulesyncSkillFrontmatter,\n RulesyncSkillFrontmatterSchema,\n} from \"../features/skills/rulesync-skill.js\";\nimport { AiDirFile } from \"../types/ai-dir.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n directoryExists,\n ensureDir,\n findFilesByGlobs,\n removeDirectory,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { stringifyFrontmatter } from \"../utils/frontmatter.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxSkillSizeBytes = 1024 * 1024; // 1MB\nconst maxSkillsCount = 1000;\n\n/**\n * Type for other files in MCP API (string-based for easier AI agent use)\n */\ntype McpSkillFile = {\n name: string;\n body: string;\n};\n\n/**\n * Convert AiDirFile to McpSkillFile\n */\nfunction aiDirFileToMcpSkillFile(file: AiDirFile): McpSkillFile {\n return {\n name: file.relativeFilePathToDirPath,\n body: file.fileBuffer.toString(\"utf-8\"),\n };\n}\n\n/**\n * Convert McpSkillFile to AiDirFile\n */\nfunction mcpSkillFileToAiDirFile(file: McpSkillFile): AiDirFile {\n return {\n relativeFilePathToDirPath: file.name,\n fileBuffer: Buffer.from(file.body, \"utf-8\"),\n };\n}\n\n/**\n * Extract directory name from relative path\n * @example \".rulesync/skills/my-skill\" -> \"my-skill\"\n */\nfunction extractDirName(relativeDirPathFromCwd: string): string {\n const dirName = basename(relativeDirPathFromCwd);\n if (!dirName) {\n throw new Error(`Invalid path: ${relativeDirPathFromCwd}`);\n }\n return dirName;\n}\n\n/**\n * Tool to list all skills from .rulesync/skills/\\*\\/SKILL.md\n */\nasync function listSkills(): Promise<\n Array<{\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n }>\n> {\n const skillsDir = join(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);\n\n try {\n // Find all skill directories (directories containing SKILL.md)\n const skillDirPaths = await findFilesByGlobs(join(skillsDir, \"*\"), { type: \"dir\" });\n\n const skills = await Promise.all(\n skillDirPaths.map(async (dirPath) => {\n const dirName = basename(dirPath);\n if (!dirName) return null;\n try {\n // Read the skill using RulesyncSkill\n const skill = await RulesyncSkill.fromDir({\n dirName,\n });\n\n const frontmatter = skill.getFrontmatter();\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read skill directory ${dirName}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return skills.filter((skill): skill is NonNullable<typeof skill> => skill !== null);\n } catch (error) {\n logger.error(\n `Failed to read skills directory (${RULESYNC_SKILLS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific skill\n */\nasync function getSkill({ relativeDirPathFromCwd }: { relativeDirPathFromCwd: string }): Promise<{\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles: McpSkillFile[];\n}> {\n checkPathTraversal({\n relativePath: relativeDirPathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const dirName = extractDirName(relativeDirPathFromCwd);\n\n try {\n const skill = await RulesyncSkill.fromDir({\n dirName,\n });\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n frontmatter: skill.getFrontmatter(),\n body: skill.getBody(),\n otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile),\n };\n } catch (error) {\n throw new Error(\n `Failed to read skill directory ${relativeDirPathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to create or update a skill (upsert operation)\n */\nasync function putSkill({\n relativeDirPathFromCwd,\n frontmatter,\n body,\n otherFiles = [],\n}: {\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles?: McpSkillFile[];\n}): Promise<{\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles: McpSkillFile[];\n}> {\n checkPathTraversal({\n relativePath: relativeDirPathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const dirName = extractDirName(relativeDirPathFromCwd);\n\n // Check file size constraint\n const estimatedSize =\n JSON.stringify(frontmatter).length +\n body.length +\n otherFiles.reduce((acc, file) => acc + file.name.length + file.body.length, 0);\n if (estimatedSize > maxSkillSizeBytes) {\n throw new Error(\n `Skill size ${estimatedSize} bytes exceeds maximum ${maxSkillSizeBytes} bytes (1MB) for ${relativeDirPathFromCwd}`,\n );\n }\n\n try {\n // Check skill count constraint\n const existingSkills = await listSkills();\n const isUpdate = existingSkills.some(\n (skill) => skill.relativeDirPathFromCwd === join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n );\n\n if (!isUpdate && existingSkills.length >= maxSkillsCount) {\n throw new Error(\n `Maximum number of skills (${maxSkillsCount}) reached in ${RULESYNC_SKILLS_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Convert McpSkillFile to AiDirFile for RulesyncSkill\n const aiDirFiles = otherFiles.map(mcpSkillFileToAiDirFile);\n\n // Create a new RulesyncSkill instance for validation\n const skill = new RulesyncSkill({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,\n dirName,\n frontmatter,\n body,\n otherFiles: aiDirFiles,\n validate: true,\n });\n\n // Ensure skill directory exists\n const skillDirPath = join(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);\n await ensureDir(skillDirPath);\n\n // Write the SKILL.md file\n const skillFilePath = join(skillDirPath, SKILL_FILE_NAME);\n const skillFileContent = stringifyFrontmatter(body, frontmatter);\n await writeFileContent(skillFilePath, skillFileContent);\n\n // Write other files\n for (const file of otherFiles) {\n // Validate file path to prevent path traversal\n checkPathTraversal({\n relativePath: file.name,\n intendedRootDir: skillDirPath,\n });\n const filePath = join(skillDirPath, file.name);\n // Ensure subdirectory exists if file has path separators\n const fileDir = join(skillDirPath, dirname(file.name));\n if (fileDir !== skillDirPath) {\n await ensureDir(fileDir);\n }\n await writeFileContent(filePath, file.body);\n }\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n frontmatter: skill.getFrontmatter(),\n body: skill.getBody(),\n otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile),\n };\n } catch (error) {\n throw new Error(\n `Failed to write skill directory ${relativeDirPathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Tool to delete a skill\n */\nasync function deleteSkill({\n relativeDirPathFromCwd,\n}: {\n relativeDirPathFromCwd: string;\n}): Promise<{\n relativeDirPathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativeDirPathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const dirName = extractDirName(relativeDirPathFromCwd);\n const skillDirPath = join(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);\n\n try {\n // Check if skill directory exists before attempting to delete\n if (await directoryExists(skillDirPath)) {\n await removeDirectory(skillDirPath);\n }\n\n return {\n relativeDirPathFromCwd: join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),\n };\n } catch (error) {\n throw new Error(\n `Failed to delete skill directory ${relativeDirPathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for other files in a skill directory\n */\nconst McpSkillFileSchema = z.object({\n name: z.string(),\n body: z.string(),\n});\n\n/**\n * Schema for skill-related tool parameters\n */\nconst skillToolSchemas = {\n listSkills: z.object({}),\n getSkill: z.object({\n relativeDirPathFromCwd: z.string(),\n }),\n putSkill: z.object({\n relativeDirPathFromCwd: z.string(),\n frontmatter: RulesyncSkillFrontmatterSchema,\n body: z.string(),\n otherFiles: z.optional(z.array(McpSkillFileSchema)),\n }),\n deleteSkill: z.object({\n relativeDirPathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for skill-related operations\n */\nexport const skillTools = {\n listSkills: {\n name: \"listSkills\",\n description: `List all skills from ${join(RULESYNC_SKILLS_RELATIVE_DIR_PATH, \"*\", SKILL_FILE_NAME)} with their frontmatter.`,\n parameters: skillToolSchemas.listSkills,\n execute: async () => {\n const skills = await listSkills();\n const output = { skills };\n return JSON.stringify(output, null, 2);\n },\n },\n getSkill: {\n name: \"getSkill\",\n description:\n \"Get detailed information about a specific skill including SKILL.md content and other files. relativeDirPathFromCwd parameter is required.\",\n parameters: skillToolSchemas.getSkill,\n execute: async (args: { relativeDirPathFromCwd: string }) => {\n const result = await getSkill({ relativeDirPathFromCwd: args.relativeDirPathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putSkill: {\n name: \"putSkill\",\n description:\n \"Create or update a skill (upsert operation). relativeDirPathFromCwd, frontmatter, and body parameters are required. otherFiles is optional.\",\n parameters: skillToolSchemas.putSkill,\n execute: async (args: {\n relativeDirPathFromCwd: string;\n frontmatter: RulesyncSkillFrontmatter;\n body: string;\n otherFiles?: McpSkillFile[];\n }) => {\n const result = await putSkill({\n relativeDirPathFromCwd: args.relativeDirPathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n otherFiles: args.otherFiles,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteSkill: {\n name: \"deleteSkill\",\n description:\n \"Delete a skill directory and all its contents. relativeDirPathFromCwd parameter is required.\",\n parameters: skillToolSchemas.deleteSkill,\n execute: async (args: { relativeDirPathFromCwd: string }) => {\n const result = await deleteSkill({ relativeDirPathFromCwd: args.relativeDirPathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { basename, join } from \"node:path\";\n\nimport { z } from \"zod/mini\";\n\nimport { RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH } from \"../constants/rulesync-paths.js\";\nimport {\n RulesyncSubagent,\n type RulesyncSubagentFrontmatter,\n RulesyncSubagentFrontmatterSchema,\n} from \"../features/subagents/rulesync-subagent.js\";\nimport { formatError } from \"../utils/error.js\";\nimport {\n checkPathTraversal,\n ensureDir,\n listDirectoryFiles,\n removeFile,\n writeFileContent,\n} from \"../utils/file.js\";\nimport { ConsoleLogger } from \"../utils/logger.js\";\n\nconst logger = new ConsoleLogger({ verbose: false, silent: true });\n\nconst maxSubagentSizeBytes = 1024 * 1024; // 1MB\nconst maxSubagentsCount = 1000;\n\n/**\n * Tool to list all subagents from .rulesync/subagents/*.md\n */\nasync function listSubagents(): Promise<\n Array<{\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n }>\n> {\n const subagentsDir = join(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);\n\n try {\n const files = await listDirectoryFiles(subagentsDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const subagents = await Promise.all(\n mdFiles.map(async (file) => {\n try {\n // Read the subagent file using RulesyncSubagent\n const subagent = await RulesyncSubagent.fromFile({\n relativeFilePath: file,\n validate: true,\n });\n\n const frontmatter = subagent.getFrontmatter();\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),\n frontmatter,\n };\n } catch (error) {\n logger.error(`Failed to read subagent file ${file}: ${formatError(error)}`);\n return null;\n }\n }),\n );\n\n // Filter out null values (failed reads)\n return subagents.filter(\n (subagent): subagent is NonNullable<typeof subagent> => subagent !== null,\n );\n } catch (error) {\n logger.error(\n `Failed to read subagents directory (${RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH}): ${formatError(error)}`,\n );\n return [];\n }\n}\n\n/**\n * Tool to get detailed information about a specific subagent\n */\nasync function getSubagent({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n try {\n const subagent = await RulesyncSubagent.fromFile({\n relativeFilePath: filename,\n validate: true,\n });\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n frontmatter: subagent.getFrontmatter(),\n body: subagent.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to read subagent file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to create or update a subagent (upsert operation)\n */\nasync function putSubagent({\n relativePathFromCwd,\n frontmatter,\n body,\n}: {\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n}): Promise<{\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n\n // Check file size constraint\n const estimatedSize = JSON.stringify(frontmatter).length + body.length;\n if (estimatedSize > maxSubagentSizeBytes) {\n throw new Error(\n `Subagent size ${estimatedSize} bytes exceeds maximum ${maxSubagentSizeBytes} bytes (1MB) for ${relativePathFromCwd}`,\n );\n }\n\n try {\n // Check subagent count constraint\n const existingSubagents = await listSubagents();\n const isUpdate = existingSubagents.some(\n (subagent) =>\n subagent.relativePathFromCwd === join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n );\n\n if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {\n throw new Error(\n `Maximum number of subagents (${maxSubagentsCount}) reached in ${RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH}`,\n );\n }\n\n // Create a new RulesyncSubagent instance\n const subagent = new RulesyncSubagent({\n outputRoot: process.cwd(),\n relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,\n relativeFilePath: filename,\n frontmatter,\n body,\n validate: true,\n });\n\n // Ensure directory exists\n const subagentsDir = join(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);\n await ensureDir(subagentsDir);\n\n // Write the file\n await writeFileContent(subagent.getFilePath(), subagent.getFileContent());\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n frontmatter: subagent.getFrontmatter(),\n body: subagent.getBody(),\n };\n } catch (error) {\n throw new Error(`Failed to write subagent file ${relativePathFromCwd}: ${formatError(error)}`, {\n cause: error,\n });\n }\n}\n\n/**\n * Tool to delete a subagent\n */\nasync function deleteSubagent({ relativePathFromCwd }: { relativePathFromCwd: string }): Promise<{\n relativePathFromCwd: string;\n}> {\n checkPathTraversal({\n relativePath: relativePathFromCwd,\n intendedRootDir: process.cwd(),\n });\n\n const filename = basename(relativePathFromCwd);\n const fullPath = join(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);\n\n try {\n await removeFile(fullPath);\n\n return {\n relativePathFromCwd: join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),\n };\n } catch (error) {\n throw new Error(\n `Failed to delete subagent file ${relativePathFromCwd}: ${formatError(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Schema for subagent-related tool parameters\n */\nconst subagentToolSchemas = {\n listSubagents: z.object({}),\n getSubagent: z.object({\n relativePathFromCwd: z.string(),\n }),\n putSubagent: z.object({\n relativePathFromCwd: z.string(),\n frontmatter: RulesyncSubagentFrontmatterSchema,\n body: z.string(),\n }),\n deleteSubagent: z.object({\n relativePathFromCwd: z.string(),\n }),\n} as const;\n\n/**\n * Tool definitions for subagent-related operations\n */\nexport const subagentTools = {\n listSubagents: {\n name: \"listSubagents\",\n description: `List all subagents from ${join(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, \"*.md\")} with their frontmatter.`,\n parameters: subagentToolSchemas.listSubagents,\n execute: async () => {\n const subagents = await listSubagents();\n const output = { subagents };\n return JSON.stringify(output, null, 2);\n },\n },\n getSubagent: {\n name: \"getSubagent\",\n description:\n \"Get detailed information about a specific subagent. relativePathFromCwd parameter is required.\",\n parameters: subagentToolSchemas.getSubagent,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await getSubagent({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n putSubagent: {\n name: \"putSubagent\",\n description:\n \"Create or update a subagent (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.\",\n parameters: subagentToolSchemas.putSubagent,\n execute: async (args: {\n relativePathFromCwd: string;\n frontmatter: RulesyncSubagentFrontmatter;\n body: string;\n }) => {\n const result = await putSubagent({\n relativePathFromCwd: args.relativePathFromCwd,\n frontmatter: args.frontmatter,\n body: args.body,\n });\n return JSON.stringify(result, null, 2);\n },\n },\n deleteSubagent: {\n name: \"deleteSubagent\",\n description: \"Delete a subagent file. relativePathFromCwd parameter is required.\",\n parameters: subagentToolSchemas.deleteSubagent,\n execute: async (args: { relativePathFromCwd: string }) => {\n const result = await deleteSubagent({ relativePathFromCwd: args.relativePathFromCwd });\n return JSON.stringify(result, null, 2);\n },\n },\n} as const;\n","import { z } from \"zod/mini\";\n\nimport {\n type RulesyncCheckFrontmatter,\n RulesyncCheckFrontmatterSchema,\n} from \"../features/checks/rulesync-check.js\";\nimport {\n type RulesyncCommandFrontmatter,\n RulesyncCommandFrontmatterSchema,\n} from \"../features/commands/rulesync-command.js\";\nimport {\n type RulesyncRuleFrontmatter,\n RulesyncRuleFrontmatterSchema,\n} from \"../features/rules/rulesync-rule.js\";\nimport {\n type RulesyncSkillFrontmatter,\n RulesyncSkillFrontmatterSchema,\n} from \"../features/skills/rulesync-skill.js\";\nimport {\n type RulesyncSubagentFrontmatter,\n RulesyncSubagentFrontmatterSchema,\n} from \"../features/subagents/rulesync-subagent.js\";\nimport { checkTools } from \"./checks.js\";\nimport { commandTools } from \"./commands.js\";\nimport { convertOptionsSchema, convertTools } from \"./convert.js\";\nimport { generateOptionsSchema, generateTools } from \"./generate.js\";\nimport { hooksTools } from \"./hooks.js\";\nimport { ignoreTools } from \"./ignore.js\";\nimport { importOptionsSchema, importTools } from \"./import.js\";\nimport { mcpTools } from \"./mcp.js\";\nimport { permissionsTools } from \"./permissions.js\";\nimport { ruleTools } from \"./rules.js\";\nimport { skillTools } from \"./skills.js\";\nimport { subagentTools } from \"./subagents.js\";\n\nconst rulesyncFeatureSchema = z.enum([\n \"rule\",\n \"command\",\n \"subagent\",\n \"skill\",\n \"check\",\n \"ignore\",\n \"mcp\",\n \"permissions\",\n \"hooks\",\n \"generate\",\n \"import\",\n \"convert\",\n]);\n\nconst rulesyncOperationSchema = z.enum([\"list\", \"get\", \"put\", \"delete\", \"run\"]);\n\nconst skillFileSchema = z.object({\n name: z.string(),\n body: z.string(),\n});\n\nconst rulesyncToolSchema = z.object({\n feature: rulesyncFeatureSchema,\n operation: rulesyncOperationSchema,\n targetPathFromCwd: z.optional(z.string()),\n frontmatter: z.optional(z.unknown()),\n body: z.optional(z.string()),\n otherFiles: z.optional(z.array(skillFileSchema)),\n content: z.optional(z.string()),\n generateOptions: z.optional(generateOptionsSchema),\n importOptions: z.optional(importOptionsSchema),\n convertOptions: z.optional(convertOptionsSchema),\n});\n\ntype RulesyncFeature = z.infer<typeof rulesyncFeatureSchema>;\ntype RulesyncOperation = z.infer<typeof rulesyncOperationSchema>;\ntype RulesyncToolArgs = z.infer<typeof rulesyncToolSchema>;\ntype RulesyncFrontmatterFeature = Exclude<\n RulesyncFeature,\n \"ignore\" | \"mcp\" | \"permissions\" | \"hooks\" | \"generate\" | \"import\" | \"convert\"\n>;\ntype RulesyncFrontmatterByFeature = {\n rule: RulesyncRuleFrontmatter;\n command: RulesyncCommandFrontmatter;\n subagent: RulesyncSubagentFrontmatter;\n skill: RulesyncSkillFrontmatter;\n check: RulesyncCheckFrontmatter;\n};\n\nconst supportedOperationsByFeature: Record<RulesyncFeature, RulesyncOperation[]> = {\n rule: [\"list\", \"get\", \"put\", \"delete\"],\n command: [\"list\", \"get\", \"put\", \"delete\"],\n subagent: [\"list\", \"get\", \"put\", \"delete\"],\n skill: [\"list\", \"get\", \"put\", \"delete\"],\n check: [\"list\", \"get\", \"put\", \"delete\"],\n ignore: [\"get\", \"put\", \"delete\"],\n mcp: [\"get\", \"put\", \"delete\"],\n permissions: [\"get\", \"put\", \"delete\"],\n hooks: [\"get\", \"put\", \"delete\"],\n generate: [\"run\"],\n import: [\"run\"],\n convert: [\"run\"],\n};\n\nfunction assertSupported({\n feature,\n operation,\n}: {\n feature: RulesyncFeature;\n operation: RulesyncOperation;\n}): void {\n const supportedOperations = supportedOperationsByFeature[feature];\n\n if (!supportedOperations.includes(operation)) {\n throw new Error(\n `Operation ${operation} is not supported for feature ${feature}. Supported operations: ${supportedOperations.join(\n \", \",\n )}`,\n );\n }\n}\n\nfunction requireTargetPath({ targetPathFromCwd, feature, operation }: RulesyncToolArgs): string {\n if (!targetPathFromCwd) {\n throw new Error(`targetPathFromCwd is required for ${feature} ${operation} operation`);\n }\n\n return targetPathFromCwd;\n}\n\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"rule\";\n frontmatter: unknown;\n}): RulesyncRuleFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"command\";\n frontmatter: unknown;\n}): RulesyncCommandFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"subagent\";\n frontmatter: unknown;\n}): RulesyncSubagentFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"skill\";\n frontmatter: unknown;\n}): RulesyncSkillFrontmatter;\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: \"check\";\n frontmatter: unknown;\n}): RulesyncCheckFrontmatter;\nfunction parseFrontmatter<Feature extends RulesyncFrontmatterFeature>({\n feature,\n frontmatter,\n}: {\n feature: Feature;\n frontmatter: unknown;\n}): RulesyncFrontmatterByFeature[Feature];\nfunction parseFrontmatter({\n feature,\n frontmatter,\n}: {\n feature: RulesyncFrontmatterFeature;\n frontmatter: unknown;\n}): RulesyncFrontmatterByFeature[RulesyncFrontmatterFeature] {\n switch (feature) {\n case \"rule\": {\n return RulesyncRuleFrontmatterSchema.parse(frontmatter);\n }\n case \"command\": {\n return RulesyncCommandFrontmatterSchema.parse(frontmatter);\n }\n case \"subagent\": {\n return RulesyncSubagentFrontmatterSchema.parse(frontmatter);\n }\n case \"skill\": {\n return RulesyncSkillFrontmatterSchema.parse(frontmatter);\n }\n case \"check\": {\n return RulesyncCheckFrontmatterSchema.parse(frontmatter);\n }\n }\n}\n\nfunction ensureBody({ body, feature, operation }: RulesyncToolArgs): string {\n if (!body) {\n throw new Error(`body is required for ${feature} ${operation} operation`);\n }\n\n return body;\n}\n\nfunction requireContent({\n content,\n feature,\n}: {\n content: string | undefined;\n feature: string;\n}): string {\n if (!content) {\n throw new Error(`content is required for ${feature} put operation`);\n }\n\n return content;\n}\n\nfunction executeRule(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return ruleTools.listRules.execute();\n }\n\n if (parsed.operation === \"get\") {\n return ruleTools.getRule.execute({ relativePathFromCwd: requireTargetPath(parsed) });\n }\n\n if (parsed.operation === \"put\") {\n return ruleTools.putRule.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"rule\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return ruleTools.deleteRule.execute({ relativePathFromCwd: requireTargetPath(parsed) });\n}\n\nfunction executeCommand(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return commandTools.listCommands.execute();\n }\n\n if (parsed.operation === \"get\") {\n return commandTools.getCommand.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n }\n\n if (parsed.operation === \"put\") {\n return commandTools.putCommand.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"command\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return commandTools.deleteCommand.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeSubagent(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return subagentTools.listSubagents.execute();\n }\n\n if (parsed.operation === \"get\") {\n return subagentTools.getSubagent.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n }\n\n if (parsed.operation === \"put\") {\n return subagentTools.putSubagent.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"subagent\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return subagentTools.deleteSubagent.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeSkill(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return skillTools.listSkills.execute();\n }\n\n if (parsed.operation === \"get\") {\n return skillTools.getSkill.execute({ relativeDirPathFromCwd: requireTargetPath(parsed) });\n }\n\n if (parsed.operation === \"put\") {\n return skillTools.putSkill.execute({\n relativeDirPathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"skill\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n otherFiles: parsed.otherFiles ?? [],\n });\n }\n\n return skillTools.deleteSkill.execute({\n relativeDirPathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeCheck(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"list\") {\n return checkTools.listChecks.execute();\n }\n\n if (parsed.operation === \"get\") {\n return checkTools.getCheck.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n }\n\n if (parsed.operation === \"put\") {\n return checkTools.putCheck.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n frontmatter: parseFrontmatter({\n feature: \"check\",\n frontmatter: parsed.frontmatter ?? {},\n }),\n body: ensureBody(parsed),\n });\n }\n\n return checkTools.deleteCheck.execute({\n relativePathFromCwd: requireTargetPath(parsed),\n });\n}\n\nfunction executeIgnore(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return ignoreTools.getIgnoreFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return ignoreTools.putIgnoreFile.execute({\n content: requireContent({ content: parsed.content, feature: \"ignore\" }),\n });\n }\n\n return ignoreTools.deleteIgnoreFile.execute();\n}\n\nfunction executeMcp(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return mcpTools.getMcpFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return mcpTools.putMcpFile.execute({\n content: requireContent({ content: parsed.content, feature: \"mcp\" }),\n });\n }\n\n return mcpTools.deleteMcpFile.execute();\n}\n\nfunction executePermissions(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return permissionsTools.getPermissionsFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return permissionsTools.putPermissionsFile.execute({\n content: requireContent({ content: parsed.content, feature: \"permissions\" }),\n });\n }\n\n return permissionsTools.deletePermissionsFile.execute();\n}\n\nfunction executeHooks(parsed: RulesyncToolArgs) {\n if (parsed.operation === \"get\") {\n return hooksTools.getHooksFile.execute();\n }\n\n if (parsed.operation === \"put\") {\n return hooksTools.putHooksFile.execute({\n content: requireContent({ content: parsed.content, feature: \"hooks\" }),\n });\n }\n\n return hooksTools.deleteHooksFile.execute();\n}\n\nfunction executeGenerate(parsed: RulesyncToolArgs) {\n // Only \"run\" operation is supported for generate feature\n return generateTools.executeGenerate.execute(parsed.generateOptions ?? {});\n}\n\nfunction executeImport(parsed: RulesyncToolArgs) {\n // Only \"run\" operation is supported for import feature\n if (!parsed.importOptions) {\n throw new Error(\"importOptions is required for import feature\");\n }\n return importTools.executeImport.execute(parsed.importOptions);\n}\n\nfunction executeConvert(parsed: RulesyncToolArgs) {\n // Only \"run\" operation is supported for convert feature\n if (!parsed.convertOptions) {\n throw new Error(\"convertOptions is required for convert feature\");\n }\n return convertTools.executeConvert.execute(parsed.convertOptions);\n}\n\nconst featureExecutors: Record<RulesyncFeature, (parsed: RulesyncToolArgs) => Promise<string>> = {\n rule: executeRule,\n command: executeCommand,\n subagent: executeSubagent,\n skill: executeSkill,\n check: executeCheck,\n ignore: executeIgnore,\n mcp: executeMcp,\n permissions: executePermissions,\n hooks: executeHooks,\n generate: executeGenerate,\n import: executeImport,\n convert: executeConvert,\n};\n\nexport const rulesyncTool = {\n name: \"rulesyncTool\",\n description:\n \"Manage Rulesync files through a single MCP tool. Features: rule/command/subagent/skill/check support list/get/put/delete; ignore/mcp/permissions/hooks support get/put/delete only; generate supports run only; import supports run only; convert supports run only. Parameters: list requires no targetPathFromCwd (lists all items); get/delete require targetPathFromCwd; put requires targetPathFromCwd, frontmatter, and body (or content for ignore/mcp/permissions/hooks); generate/run uses generateOptions to configure generation; import/run uses importOptions to configure import; convert/run uses convertOptions to configure conversion.\",\n parameters: rulesyncToolSchema,\n execute: async (args: RulesyncToolArgs) => {\n const parsed = rulesyncToolSchema.parse(args);\n\n assertSupported({ feature: parsed.feature, operation: parsed.operation });\n\n const executor = featureExecutors[parsed.feature];\n if (!executor) {\n throw new Error(`Unknown feature: ${parsed.feature}`);\n }\n\n return executor(parsed);\n },\n} as const;\n","import { FastMCP } from \"fastmcp\";\n\nimport { rulesyncTool } from \"../../mcp/tools.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\n/**\n * MCP command that starts the MCP server\n */\nexport async function mcpCommand(logger: Logger, { version }: { version: string }): Promise<void> {\n const server = new FastMCP({\n name: \"Rulesync MCP Server\",\n version: version as `${number}.${number}.${number}`,\n instructions:\n \"This server handles Rulesync files including rules, commands, MCP, ignore files, subagents and skills for any AI agents. It should be used when you need those files.\",\n });\n\n server.addTool(rulesyncTool);\n\n // Start server with stdio transport (for spawned processes)\n logger.info(\"Rulesync MCP server started via stdio\");\n\n // Start the server - this blocks execution and runs the MCP server\n // The void operator explicitly marks this as intentionally not awaited\n void server.start({\n transportType: \"stdio\",\n });\n}\n","import { join } from \"node:path\";\n\nimport { ConfigResolver } from \"../../config/config-resolver.js\";\nimport {\n RULESYNC_CONFIG_RELATIVE_FILE_PATH,\n RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH,\n} from \"../../constants/rulesync-paths.js\";\nimport { fileExists } from \"../../utils/file.js\";\n\nexport type ResolveGitignoreTargetsParams = {\n readonly cliTargets: readonly string[] | undefined;\n readonly cwd?: string;\n};\n\n/**\n * Resolve the list of targets to pass to `gitignoreCommand`.\n *\n * Precedence:\n * 1. Explicit `--targets` CLI option wins.\n * 2. If neither rulesync.jsonc nor rulesync.local.jsonc exists, return\n * `undefined` so all supported tools' entries are emitted. Otherwise a\n * user without a config file would silently get only the default\n * `[\"agentsmd\"]` target, which is a surprising behavior change.\n * 3. If `gitignoreTargetsOnly` is true (the default), return the config's\n * `targets` with `agentsmd` always appended. `AGENTS.md` is a de facto\n * standard file read by many AI tools regardless of which targets the\n * user selected, so its gitignore entries must always be emitted to\n * prevent accidental commits of generated rule files.\n * 4. Otherwise return `undefined` to emit entries for every supported tool.\n */\nexport const resolveGitignoreTargets = async ({\n cliTargets,\n cwd = process.cwd(),\n}: ResolveGitignoreTargetsParams): Promise<readonly string[] | undefined> => {\n if (cliTargets !== undefined) {\n return cliTargets;\n }\n\n const baseConfigPath = join(cwd, RULESYNC_CONFIG_RELATIVE_FILE_PATH);\n const localConfigPath = join(cwd, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);\n const [hasBase, hasLocal] = await Promise.all([\n fileExists(baseConfigPath),\n fileExists(localConfigPath),\n ]);\n\n if (!hasBase && !hasLocal) {\n return undefined;\n }\n\n const config = await ConfigResolver.resolve({});\n if (config.getGitignoreTargetsOnly()) {\n const targets = config.getTargets();\n if (targets.includes(\"agentsmd\")) {\n return targets;\n }\n return [...targets, \"agentsmd\"];\n }\n return undefined;\n};\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { Readable, Transform } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\n\nimport type { GitHubRelease, GitHubReleaseAsset } from \"../types/fetch.js\";\nimport { GitHubClient } from \"./github-client.js\";\n\nconst RULESYNC_REPO_OWNER = \"dyoshikawa\";\nconst RULESYNC_REPO_NAME = \"rulesync\";\n\n/**\n * GitHub releases URL for manual download instructions\n */\nconst RELEASES_URL = `https://github.com/${RULESYNC_REPO_OWNER}/${RULESYNC_REPO_NAME}/releases`;\n\n/**\n * Maximum download size (500MB) to prevent memory exhaustion\n */\nconst MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;\n\n/**\n * Allowed domains for downloading release assets\n */\nconst ALLOWED_DOWNLOAD_DOMAINS = [\n \"github.com\",\n \"objects.githubusercontent.com\",\n \"github-releases.githubusercontent.com\",\n \"release-assets.githubusercontent.com\",\n];\n\n/**\n * Execution environment types for rulesync\n */\nexport type ExecutionEnvironment = \"single-binary\" | \"homebrew\" | \"npm\";\n\n/**\n * Update check result\n */\nexport type UpdateCheckResult = {\n currentVersion: string;\n latestVersion: string;\n hasUpdate: boolean;\n release: GitHubRelease;\n};\n\n/**\n * Custom error for permission issues during update\n */\nexport class UpdatePermissionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"UpdatePermissionError\";\n }\n}\n\n/**\n * Detect the execution environment of rulesync.\n *\n * Uses process.execPath (the Node.js/Bun binary) and process.argv[1] (the script being executed)\n * to determine how rulesync was installed.\n */\nexport function detectExecutionEnvironment(): ExecutionEnvironment {\n const execPath = process.execPath;\n const scriptPath = process.argv[1] ?? \"\";\n\n // Single binary detection: the executable itself is named rulesync\n const isRulesyncBinary = /rulesync(-[a-z0-9]+(-[a-z0-9]+)?)?(\\.exe)?$/i.test(execPath);\n if (isRulesyncBinary) {\n // Check if the rulesync binary itself is in a Homebrew path\n if (execPath.includes(\"/homebrew/\") || execPath.includes(\"/Cellar/\")) {\n return \"homebrew\";\n }\n return \"single-binary\";\n }\n\n // Homebrew detection via script path: e.g. /opt/homebrew/lib/node_modules/rulesync/...\n if (\n (scriptPath.includes(\"/homebrew/\") || scriptPath.includes(\"/Cellar/\")) &&\n scriptPath.includes(\"rulesync\")\n ) {\n return \"homebrew\";\n }\n\n return \"npm\";\n}\n\n/**\n * Get the asset name for the current platform\n */\nexport function getPlatformAssetName(): string | null {\n const platform = os.platform();\n const arch = os.arch();\n\n // Map Node.js platform/arch to asset names\n const platformMap: Record<string, string> = {\n darwin: \"darwin\",\n linux: \"linux\",\n win32: \"windows\",\n };\n\n const archMap: Record<string, string> = {\n x64: \"x64\",\n arm64: \"arm64\",\n };\n\n const platformName = platformMap[platform];\n const archName = archMap[arch];\n\n if (!platformName || !archName) {\n return null;\n }\n\n const extension = platform === \"win32\" ? \".exe\" : \"\";\n return `rulesync-${platformName}-${archName}${extension}`;\n}\n\n/**\n * Normalize version string by removing leading 'v' and stripping pre-release suffix\n */\nexport function normalizeVersion(v: string): string {\n // Remove leading 'v' and strip pre-release suffix (e.g., \"1.2.3-beta.1\" -> \"1.2.3\")\n return v.replace(/^v/, \"\").replace(/-.*$/, \"\");\n}\n\n/**\n * Compare semantic versions\n * Returns: 1 if a > b, -1 if a < b, 0 if equal\n */\nexport function compareVersions(a: string, b: string): number {\n const aParts = normalizeVersion(a).split(\".\").map(Number);\n const bParts = normalizeVersion(b).split(\".\").map(Number);\n\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const aNum = aParts[i] ?? 0;\n const bNum = bParts[i] ?? 0;\n if (!Number.isFinite(aNum) || !Number.isFinite(bNum)) {\n throw new Error(`Invalid version format: cannot compare \"${a}\" and \"${b}\"`);\n }\n if (aNum > bNum) return 1;\n if (aNum < bNum) return -1;\n }\n return 0;\n}\n\n/**\n * Validate that a download URL is safe (HTTPS + allowed GitHub domain + repo path for github.com)\n */\nexport function validateDownloadUrl(url: string): void {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(`Invalid download URL: ${url}`);\n }\n\n if (parsed.protocol !== \"https:\") {\n throw new Error(`Download URL must use HTTPS: ${url}`);\n }\n\n const isAllowed = ALLOWED_DOWNLOAD_DOMAINS.some((domain) => parsed.hostname === domain);\n if (!isAllowed) {\n throw new Error(\n `Download URL domain \"${parsed.hostname}\" is not in the allowed list: ${ALLOWED_DOWNLOAD_DOMAINS.join(\", \")}`,\n );\n }\n\n // For github.com URLs, validate the path starts with the expected repo\n if (parsed.hostname === \"github.com\") {\n const expectedPrefix = `/${RULESYNC_REPO_OWNER}/${RULESYNC_REPO_NAME}/`;\n if (!parsed.pathname.startsWith(expectedPrefix)) {\n throw new Error(\n `Download URL path must belong to ${RULESYNC_REPO_OWNER}/${RULESYNC_REPO_NAME}: ${url}`,\n );\n }\n }\n}\n\n/**\n * Check for updates\n */\nexport async function checkForUpdate(\n currentVersion: string,\n token?: string,\n): Promise<UpdateCheckResult> {\n const client = new GitHubClient({\n token: GitHubClient.resolveToken(token),\n });\n\n const release = await client.getLatestRelease(RULESYNC_REPO_OWNER, RULESYNC_REPO_NAME);\n const latestVersion = normalizeVersion(release.tag_name);\n const normalizedCurrentVersion = normalizeVersion(currentVersion);\n\n return {\n currentVersion: normalizedCurrentVersion,\n latestVersion,\n hasUpdate: compareVersions(latestVersion, normalizedCurrentVersion) > 0,\n release,\n };\n}\n\n/**\n * Find asset by name in release\n */\nfunction findAsset(release: GitHubRelease, assetName: string): GitHubReleaseAsset | null {\n return release.assets.find((asset) => asset.name === assetName) ?? null;\n}\n\n/**\n * Download a file from URL to a destination path using streaming to limit memory usage.\n * Validates both the initial URL and the final URL after redirects.\n */\nasync function downloadFile(url: string, destPath: string): Promise<void> {\n validateDownloadUrl(url);\n\n const response = await fetch(url, {\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new Error(`Failed to download ${url}: HTTP ${response.status}`);\n }\n\n // Validate the final URL after redirects to prevent redirect-based bypass\n if (response.url) {\n validateDownloadUrl(response.url);\n }\n\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength && Number(contentLength) > MAX_DOWNLOAD_SIZE) {\n throw new Error(\n `Download too large: ${contentLength} bytes exceeds limit of ${MAX_DOWNLOAD_SIZE} bytes`,\n );\n }\n\n if (!response.body) {\n throw new Error(\"Response body is empty\");\n }\n\n // Stream the response to file with a size limit check\n const fileStream = fs.createWriteStream(destPath);\n let downloadedBytes = 0;\n\n const bodyReader = Readable.fromWeb(response.body as import(\"node:stream/web\").ReadableStream);\n\n const sizeChecker = new Transform({\n transform(chunk, _encoding, callback) {\n downloadedBytes += (chunk as Buffer).length;\n if (downloadedBytes > MAX_DOWNLOAD_SIZE) {\n callback(\n new Error(\n `Download too large: exceeded limit of ${MAX_DOWNLOAD_SIZE} bytes during streaming`,\n ),\n );\n return;\n }\n callback(null, chunk);\n },\n });\n\n await pipeline(bodyReader, sizeChecker, fileStream);\n}\n\n/**\n * Calculate SHA256 checksum of a file\n */\nasync function calculateSha256(filePath: string): Promise<string> {\n const content = await fs.promises.readFile(filePath);\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/**\n * Parse SHA256SUMS file content\n */\nexport function parseSha256Sums(content: string): Map<string, string> {\n const result = new Map<string, string>();\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n // Format: \"hash filename\" (two spaces between hash and filename)\n const match = /^([a-f0-9]{64})\\s+(.+)$/.exec(trimmed);\n if (match && match[1] && match[2]) {\n result.set(match[2].trim(), match[1]);\n }\n }\n return result;\n}\n\n/**\n * Update options\n */\nexport type UpdateOptions = {\n force?: boolean;\n token?: string;\n};\n\n/**\n * Resolve the platform binary asset and the mandatory SHA256SUMS asset from a\n * release, throwing with manual-download guidance when either is unavailable.\n */\nfunction resolveUpdateAssets(release: GitHubRelease): {\n assetName: string;\n binaryAsset: GitHubReleaseAsset;\n checksumAsset: GitHubReleaseAsset;\n} {\n // Get platform-specific asset name\n const assetName = getPlatformAssetName();\n if (!assetName) {\n throw new Error(\n `Unsupported platform: ${os.platform()} ${os.arch()}. Please download manually from ${RELEASES_URL}`,\n );\n }\n\n // Find the binary asset\n const binaryAsset = findAsset(release, assetName);\n if (!binaryAsset) {\n throw new Error(\n `Binary for ${assetName} not found in release. Please download manually from ${RELEASES_URL}`,\n );\n }\n\n // Find the SHA256SUMS asset for verification (mandatory)\n const checksumAsset = findAsset(release, \"SHA256SUMS\");\n if (!checksumAsset) {\n throw new Error(\n `SHA256SUMS not found in release. Cannot verify download integrity. Please download manually from ${RELEASES_URL}`,\n );\n }\n\n return { assetName, binaryAsset, checksumAsset };\n}\n\n/**\n * Download the binary and SHA256SUMS into the temp directory, then verify the\n * binary's checksum. Throws when the checksum entry is missing or mismatched.\n */\nasync function downloadAndVerifyBinary(params: {\n tempDir: string;\n assetName: string;\n binaryAsset: GitHubReleaseAsset;\n checksumAsset: GitHubReleaseAsset;\n}): Promise<string> {\n const { tempDir, assetName, binaryAsset, checksumAsset } = params;\n const tempBinaryPath = path.join(tempDir, assetName);\n\n // Download the binary\n await downloadFile(binaryAsset.browser_download_url, tempBinaryPath);\n\n // Verify checksum (mandatory)\n const checksumsPath = path.join(tempDir, \"SHA256SUMS\");\n await downloadFile(checksumAsset.browser_download_url, checksumsPath);\n\n const checksumsContent = await fs.promises.readFile(checksumsPath, \"utf-8\");\n const checksums = parseSha256Sums(checksumsContent);\n const expectedChecksum = checksums.get(assetName);\n\n if (!expectedChecksum) {\n throw new Error(\n `Checksum entry for \"${assetName}\" not found in SHA256SUMS. Cannot verify download integrity.`,\n );\n }\n\n const actualChecksum = await calculateSha256(tempBinaryPath);\n if (actualChecksum !== expectedChecksum) {\n throw new Error(\n `Checksum verification failed. Expected: ${expectedChecksum}, Got: ${actualChecksum}. The download may be corrupted.`,\n );\n }\n\n return tempBinaryPath;\n}\n\n/**\n * Replace the running executable at `currentExePath` with the verified binary,\n * preferring an atomic rename and falling back to a direct cross-filesystem copy.\n */\nasync function replaceCurrentBinary(params: {\n tempBinaryPath: string;\n currentExePath: string;\n currentDir: string;\n}): Promise<void> {\n const { tempBinaryPath, currentExePath, currentDir } = params;\n // Attempt atomic replacement via rename (works when on the same filesystem)\n const tempInPlace = path.join(currentDir, `.rulesync-update-${crypto.randomUUID()}`);\n try {\n await fs.promises.copyFile(tempBinaryPath, tempInPlace);\n if (os.platform() !== \"win32\") {\n await fs.promises.chmod(tempInPlace, 0o755);\n }\n await fs.promises.rename(tempInPlace, currentExePath);\n } catch {\n // Cleanup temp-in-place file on failure, then fall back to direct copy\n try {\n await fs.promises.unlink(tempInPlace);\n } catch {\n // Ignore cleanup errors\n }\n // Fallback: direct copy (non-atomic but works across filesystems)\n await fs.promises.copyFile(tempBinaryPath, currentExePath);\n if (os.platform() !== \"win32\") {\n await fs.promises.chmod(currentExePath, 0o755);\n }\n }\n}\n\n/**\n * Install the verified binary over the current executable, backing it up first\n * and restoring from backup on failure. Returns whether the restore failed so\n * the caller can preserve the temp directory for manual recovery.\n */\nasync function installVerifiedBinary(params: {\n tempDir: string;\n tempBinaryPath: string;\n currentVersion: string;\n latestVersion: string;\n}): Promise<{ message: string; restoreFailed: boolean }> {\n const { tempDir, tempBinaryPath, currentVersion, latestVersion } = params;\n\n // Resolve symlinks to get the real executable path\n const currentExePath = await fs.promises.realpath(process.execPath);\n const currentDir = path.dirname(currentExePath);\n\n // Backup current binary to temp directory (not predictable path)\n const backupPath = path.join(tempDir, \"rulesync.backup\");\n try {\n await fs.promises.copyFile(currentExePath, backupPath);\n } catch (error) {\n if (isPermissionError(error)) {\n throw new UpdatePermissionError(\n `Permission denied: Cannot read ${currentExePath}. Try running with sudo.`,\n );\n }\n throw error;\n }\n\n try {\n await replaceCurrentBinary({ tempBinaryPath, currentExePath, currentDir });\n return {\n message: `Successfully updated from ${currentVersion} to ${latestVersion}`,\n restoreFailed: false,\n };\n } catch (error) {\n // Restore from backup on failure\n try {\n await fs.promises.copyFile(backupPath, currentExePath);\n } catch {\n throw new RestoreFailedError(\n new Error(\n `Failed to replace binary and restore failed. Backup is preserved at: ${backupPath} (in ${tempDir}). ` +\n `Please manually copy it to ${currentExePath}. Original error: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n ),\n );\n }\n if (isPermissionError(error)) {\n throw new UpdatePermissionError(\n `Permission denied: Cannot write to ${path.dirname(currentExePath)}. Try running with sudo.`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Internal marker wrapping the error thrown when both the binary replacement\n * and the backup restore fail. The caller unwraps it so the temp directory is\n * preserved for manual recovery (mirrors the original inline `restoreFailed`\n * flag behavior).\n */\nclass RestoreFailedError extends Error {\n override readonly cause: Error;\n constructor(cause: Error) {\n super(cause.message);\n this.name = \"RestoreFailedError\";\n this.cause = cause;\n }\n}\n\n/**\n * Perform the binary update\n */\nexport async function performBinaryUpdate(\n currentVersion: string,\n options: UpdateOptions = {},\n): Promise<string> {\n const { force = false, token } = options;\n\n // Check for updates\n const updateCheck = await checkForUpdate(currentVersion, token);\n\n if (!updateCheck.hasUpdate && !force) {\n return `Already at the latest version (${currentVersion})`;\n }\n\n const { assetName, binaryAsset, checksumAsset } = resolveUpdateAssets(updateCheck.release);\n\n // Create temporary directory for download\n const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), \"rulesync-update-\"));\n let restoreFailed = false;\n\n try {\n // Set restrictive permissions on temp directory (Unix only)\n if (os.platform() !== \"win32\") {\n await fs.promises.chmod(tempDir, 0o700);\n }\n\n const tempBinaryPath = await downloadAndVerifyBinary({\n tempDir,\n assetName,\n binaryAsset,\n checksumAsset,\n });\n\n const installed = await installVerifiedBinary({\n tempDir,\n tempBinaryPath,\n currentVersion,\n latestVersion: updateCheck.latestVersion,\n });\n restoreFailed = installed.restoreFailed;\n return installed.message;\n } catch (error) {\n if (error instanceof RestoreFailedError) {\n restoreFailed = true;\n throw error.cause;\n }\n throw error;\n } finally {\n // Skip cleanup if restore failed, so the backup is preserved for manual recovery\n if (!restoreFailed) {\n try {\n await fs.promises.rm(tempDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n}\n\n/**\n * Check if an error is a permission error\n */\nfunction isPermissionError(error: unknown): boolean {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n const record = error as Record<string, unknown>;\n return record[\"code\"] === \"EACCES\" || record[\"code\"] === \"EPERM\";\n }\n return false;\n}\n\n/**\n * Get upgrade instructions for npm installation\n */\nexport function getNpmUpgradeInstructions(): string {\n return `This rulesync installation was installed via npm/npx.\n\nTo upgrade, run one of the following commands:\n\n Global installation:\n npm install -g rulesync@latest\n\n Project dependency:\n npm install rulesync@latest\n\n Or use npx to always run the latest version:\n npx rulesync@latest --version`;\n}\n\n/**\n * Get upgrade instructions for Homebrew installation\n */\nexport function getHomebrewUpgradeInstructions(): string {\n return `This rulesync installation was installed via Homebrew.\n\nTo upgrade, run:\n brew upgrade rulesync`;\n}\n","import { GitHubClientError } from \"../../lib/github-client.js\";\nimport {\n UpdatePermissionError,\n checkForUpdate,\n detectExecutionEnvironment,\n getHomebrewUpgradeInstructions,\n getNpmUpgradeInstructions,\n performBinaryUpdate,\n} from \"../../lib/update.js\";\nimport { CLIError, ErrorCodes } from \"../../types/json-output.js\";\nimport type { Logger } from \"../../utils/logger.js\";\n\n/**\n * Update command options\n */\nexport type UpdateCommandOptions = {\n check?: boolean;\n force?: boolean;\n verbose?: boolean;\n silent?: boolean;\n token?: string;\n};\n\n/**\n * Update command handler\n */\nexport async function updateCommand(\n logger: Logger,\n currentVersion: string,\n options: UpdateCommandOptions,\n): Promise<void> {\n const { check = false, force = false, token } = options;\n\n try {\n const environment = detectExecutionEnvironment();\n logger.debug(`Detected environment: ${environment}`);\n\n if (environment === \"npm\") {\n logger.info(getNpmUpgradeInstructions());\n return;\n }\n\n if (environment === \"homebrew\") {\n logger.info(getHomebrewUpgradeInstructions());\n return;\n }\n\n // Single-binary mode\n if (check) {\n // Check-only mode\n logger.info(\"Checking for updates...\");\n const updateCheck = await checkForUpdate(currentVersion, token);\n\n // Capture JSON data if in JSON mode\n if (logger.jsonMode) {\n logger.captureData(\"currentVersion\", updateCheck.currentVersion);\n logger.captureData(\"latestVersion\", updateCheck.latestVersion);\n logger.captureData(\"updateAvailable\", updateCheck.hasUpdate);\n logger.captureData(\n \"message\",\n updateCheck.hasUpdate\n ? `Update available: ${updateCheck.currentVersion} -> ${updateCheck.latestVersion}`\n : `Already at the latest version (${updateCheck.currentVersion})`,\n );\n }\n\n if (updateCheck.hasUpdate) {\n logger.success(\n `Update available: ${updateCheck.currentVersion} -> ${updateCheck.latestVersion}`,\n );\n } else {\n logger.info(`Already at the latest version (${updateCheck.currentVersion})`);\n }\n return;\n }\n\n // Perform update\n logger.info(\"Checking for updates...\");\n const message = await performBinaryUpdate(currentVersion, { force, token });\n logger.success(message);\n } catch (error) {\n if (error instanceof GitHubClientError) {\n // Include auth hints in error message for JSON mode\n const authHint =\n error.statusCode === 401 || error.statusCode === 403\n ? \" Tip: Set GITHUB_TOKEN or GH_TOKEN environment variable, or use `GITHUB_TOKEN=$(gh auth token) rulesync update ...`\"\n : \"\";\n throw new CLIError(\n `GitHub API Error: ${error.message}.${authHint}`,\n ErrorCodes.UPDATE_FAILED,\n );\n } else if (error instanceof UpdatePermissionError) {\n throw new CLIError(\n `${error.message} Tip: Run with elevated privileges (e.g., sudo rulesync update)`,\n ErrorCodes.UPDATE_FAILED,\n );\n }\n throw error;\n }\n}\n","import { Command } from \"commander\";\n\nimport { CLIError } from \"../types/json-output.js\";\nimport { formatError } from \"../utils/error.js\";\nimport { ConsoleLogger, JsonLogger, Logger } from \"../utils/logger.js\";\n\nexport function createLogger({\n name,\n globalOpts,\n getVersion,\n}: {\n name: string;\n globalOpts: Record<string, unknown>;\n getVersion: () => string;\n}): Logger {\n return globalOpts.json\n ? new JsonLogger({ command: name, version: getVersion() })\n : new ConsoleLogger();\n}\n\nexport function wrapCommand({\n name,\n errorCode,\n handler,\n getVersion,\n loggerFactory = createLogger,\n}: {\n name: string;\n errorCode: string;\n handler: (\n logger: Logger,\n options: unknown,\n globalOpts: Record<string, unknown>,\n positionalArgs: unknown[],\n ) => Promise<void>;\n getVersion: () => string;\n loggerFactory?: (params: {\n name: string;\n globalOpts: Record<string, unknown>;\n getVersion: () => string;\n }) => Logger;\n}) {\n return async (...args: unknown[]) => {\n // Commander passes variable args based on command signature:\n // - No positional: (options, command)\n // - With positional: (arg1, arg2, ..., options, command)\n // The last two are always (options, command)\n const command = args[args.length - 1] as Command;\n const options = args[args.length - 2] as Record<string, unknown>;\n const positionalArgs = args.slice(0, -2);\n const globalOpts = command.parent?.opts() ?? {};\n const logger = loggerFactory({ name, globalOpts, getVersion });\n logger.configure({\n verbose: Boolean(globalOpts.verbose) || Boolean(options.verbose),\n silent: Boolean(globalOpts.silent) || Boolean(options.silent),\n });\n\n try {\n await handler(logger, options, globalOpts, positionalArgs);\n logger.outputJson(true);\n } catch (error) {\n const code = error instanceof CLIError ? error.code : errorCode;\n const errorArg = error instanceof Error ? error : formatError(error);\n logger.error(errorArg, code);\n process.exit(error instanceof CLIError ? error.exitCode : 1);\n }\n };\n}\n","#!/usr/bin/env node\n\nimport { Command } from \"commander\";\n\nimport { ALL_FEATURES, RulesyncFeatures } from \"../types/features.js\";\nimport { FetchOptions } from \"../types/fetch.js\";\nimport { formatError } from \"../utils/error.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { parseCommaSeparatedList } from \"../utils/parse-comma-separated-list.js\";\nimport { convertCommand, ConvertOptions } from \"./commands/convert.js\";\nimport { fetchCommand } from \"./commands/fetch.js\";\nimport { generateCommand, GenerateOptions } from \"./commands/generate.js\";\nimport { gitignoreCommand } from \"./commands/gitignore.js\";\nimport { importCommand, ImportOptions } from \"./commands/import.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { INSTALL_MODES, InstallMode, installCommand } from \"./commands/install.js\";\nimport { mcpCommand } from \"./commands/mcp.js\";\nimport { resolveGitignoreTargets } from \"./commands/resolve-gitignore-targets.js\";\nimport { updateCommand, UpdateCommandOptions } from \"./commands/update.js\";\nimport { wrapCommand as _wrapCommand } from \"./wrap-command.js\";\n\nconst getVersion = () => \"14.0.1\";\n\nfunction wrapCommand(\n name: string,\n errorCode: string,\n handler: (\n logger: Logger,\n options: unknown,\n globalOpts: Record<string, unknown>,\n positionalArgs: unknown[],\n ) => Promise<void>,\n) {\n return _wrapCommand({ name, errorCode, handler, getVersion });\n}\n\nconst main = async () => {\n const program = new Command();\n\n const version = getVersion();\n\n program\n .name(\"rulesync\")\n .description(\"Unified AI rules management CLI tool\")\n .version(version, \"-v, --version\", \"Show version\")\n .option(\"-j, --json\", \"Output results as JSON\");\n\n program\n .command(\"init\")\n .description(\"Initialize rulesync in current directory\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"init\", \"INIT_FAILED\", async (logger) => {\n await initCommand(logger);\n }),\n );\n\n program\n .command(\"gitignore\")\n .description(\"Add generated files to .gitignore\")\n .option(\n \"-t, --targets <tools>\",\n \"Comma-separated list of tools to include (e.g., 'claudecode,copilot' or '*' for all)\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to include (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"gitignore\", \"GITIGNORE_FAILED\", async (logger, options) => {\n const cliTargets = (options as { targets?: string[] }).targets;\n const cliFeatures = (options as { features?: RulesyncFeatures }).features;\n\n const resolvedTargets = await resolveGitignoreTargets({ cliTargets });\n\n await gitignoreCommand(logger, {\n targets: resolvedTargets ? [...resolvedTargets] : undefined,\n features: cliFeatures,\n });\n }),\n );\n\n program\n .command(\"fetch <source>\")\n .description(\"Fetch files from a Git repository (GitHub/GitLab)\")\n .option(\n \"-t, --target <target>\",\n \"Target format to interpret files as (e.g., 'rulesync', 'claudecode'). Default: rulesync\",\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to fetch (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-r, --ref <ref>\", \"Branch, tag, or commit SHA to fetch from\")\n .option(\"-p, --path <path>\", \"Subdirectory path within the repository\")\n .option(\"-o, --output <dir>\", \"Output directory (default: .rulesync)\")\n .option(\n \"-c, --conflict <strategy>\",\n \"Conflict resolution strategy: skip, overwrite (default: overwrite)\",\n )\n .option(\"--token <token>\", \"Git provider token for private repositories\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"fetch\", \"FETCH_FAILED\", async (logger, options, _globalOpts, positionalArgs) => {\n const source = positionalArgs[0] as string;\n await fetchCommand(logger, { ...(options as FetchOptions), source });\n }),\n );\n\n program\n .command(\"import\")\n .description(\"Import configurations from AI tools to rulesync format\")\n .option(\n \"-t, --targets <tool>\",\n \"Tool to import from (e.g., 'copilot', 'cursor', 'cline')\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to import (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .option(\"-g, --global\", \"Import for global(user scope) configuration files\")\n .action(\n wrapCommand(\"import\", \"IMPORT_FAILED\", async (logger, options) => {\n await importCommand(logger, options as ImportOptions);\n }),\n );\n\n program\n .command(\"convert\")\n .description(\n \"Convert configurations from one AI tool to other AI tools without writing .rulesync/ files\",\n )\n .requiredOption(\"--from <tool>\", \"Source tool to convert from (e.g., 'cursor', 'claudecode')\")\n .requiredOption(\n \"--to <tools>\",\n \"Comma-separated list of destination tools (e.g., 'copilot,claudecode')\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to convert (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .option(\"-g, --global\", \"Convert for global(user scope) configuration files\")\n .option(\"--dry-run\", \"Dry run: show changes without writing files\")\n .action(\n wrapCommand(\"convert\", \"CONVERT_FAILED\", async (logger, options) => {\n await convertCommand(logger, options as ConvertOptions);\n }),\n );\n\n program\n .command(\"mcp\")\n .description(\"Start MCP server for rulesync\")\n .action(\n wrapCommand(\"mcp\", \"MCP_FAILED\", async (logger, _options) => {\n await mcpCommand(logger, { version });\n }),\n );\n\n program\n .command(\"install\")\n .description(\"Install skills/primitives from declarative sources (rulesync.jsonc) or apm.yml\")\n .option(\n \"--mode <mode>\",\n `Install layout to produce (${INSTALL_MODES.join(\"|\")}). Default: rulesync`,\n )\n .option(\"--update\", \"Force re-resolve all source refs, ignoring lockfile\")\n .option(\n \"--frozen\",\n \"Fail if lockfile is missing or out of sync (for CI); fetches missing skills using locked refs\",\n )\n .option(\"--token <token>\", \"GitHub token for private repos\")\n .option(\"-c, --config <path>\", \"Path to configuration file\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"install\", \"INSTALL_FAILED\", async (logger, options) => {\n const rawMode = (options as { mode?: string }).mode;\n const mode = parseInstallMode(rawMode);\n await installCommand(logger, {\n mode,\n update: (options as { update?: boolean }).update,\n frozen: (options as { frozen?: boolean }).frozen,\n token: (options as { token?: string }).token,\n configPath: (options as { config?: string }).config,\n verbose: (options as { verbose?: boolean }).verbose,\n silent: (options as { silent?: boolean }).silent,\n });\n }),\n );\n\n program\n .command(\"generate\")\n .description(\"Generate configuration files for AI tools\")\n .option(\n \"-t, --targets <tools>\",\n \"Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)\",\n parseCommaSeparatedList,\n )\n .option(\n \"-f, --features <features>\",\n `Comma-separated list of features to generate (${ALL_FEATURES.join(\",\")}) or '*' for all`,\n parseCommaSeparatedList,\n )\n .option(\"--delete\", \"Delete all existing files in output directories before generating\")\n .option(\n \"-o, --output-roots <paths>\",\n \"Output root directories to generate files into (comma-separated for multiple paths)\",\n parseCommaSeparatedList,\n )\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .option(\"-c, --config <path>\", \"Path to configuration file\")\n .option(\"-g, --global\", \"Generate for global(user scope) configuration files\")\n .option(\n \"--simulate-commands\",\n \"Generate simulated commands. This feature is only available for copilot, cursor and codexcli.\",\n )\n .option(\n \"--simulate-subagents\",\n \"Generate simulated subagents. This feature is only available for copilot and codexcli.\",\n )\n .option(\n \"--simulate-skills\",\n \"Generate simulated skills. This feature is only available for copilot, cursor and codexcli.\",\n )\n .option(\n \"--input-root <path>\",\n \"Path to the directory containing .rulesync/ (parent of .rulesync/)\",\n )\n .option(\"--dry-run\", \"Dry run: show changes without writing files\")\n .option(\"--check\", \"Check if files are up to date (exits with code 1 if changes needed)\")\n .action(\n wrapCommand(\"generate\", \"GENERATION_FAILED\", async (logger, options) => {\n await generateCommand(logger, options as GenerateOptions);\n }),\n );\n\n program\n .command(\"update\")\n .description(\"Update rulesync to the latest version\")\n .option(\"--check\", \"Check for updates without installing\")\n .option(\"--force\", \"Force update even if already at latest version\")\n .option(\"--token <token>\", \"GitHub token for API access\")\n .option(\"-V, --verbose\", \"Verbose output\")\n .option(\"-s, --silent\", \"Suppress all output\")\n .action(\n wrapCommand(\"update\", \"UPDATE_FAILED\", async (logger, options) => {\n await updateCommand(logger, version, options as UpdateCommandOptions);\n }),\n );\n\n program.parse();\n};\n\nfunction parseInstallMode(raw: string | undefined): InstallMode | undefined {\n if (raw === undefined) return undefined;\n const match = INSTALL_MODES.find((m) => m === raw);\n if (!match) {\n throw new Error(`Invalid --mode value \"${raw}\". Expected one of: ${INSTALL_MODES.join(\", \")}.`);\n }\n return match;\n}\n\nmain().catch((error) => {\n console.error(formatError(error));\n process.exit(1);\n});\n"],"mappings":"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"}