@intlayer/engine 9.5.12 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/installSkills/skills/cli.md +28 -1
- package/dist/assets/installSkills/skills/compat.md +1 -1
- package/dist/assets/installSkills/skills/dev-tools.md +8 -6
- package/dist/cjs/cli.cjs +2 -0
- package/dist/cjs/init/index.cjs +12 -2
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/packageManager.cjs +1 -1
- package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
- package/dist/cjs/installMCP/installMCP.cjs +35 -25
- package/dist/cjs/installMCP/installMCP.cjs.map +1 -1
- package/dist/cjs/installSkills/index.cjs +26 -1
- package/dist/cjs/installSkills/index.cjs.map +1 -1
- package/dist/cjs/listGitFiles.cjs +3 -5
- package/dist/cjs/listGitFiles.cjs.map +1 -1
- package/dist/cjs/listProjects.cjs +1 -2
- package/dist/cjs/listProjects.cjs.map +1 -1
- package/dist/esm/cli.mjs +3 -3
- package/dist/esm/init/index.mjs +12 -2
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/packageManager.mjs +1 -1
- package/dist/esm/init/utils/packageManager.mjs.map +1 -1
- package/dist/esm/installMCP/installMCP.mjs +35 -25
- package/dist/esm/installMCP/installMCP.mjs.map +1 -1
- package/dist/esm/installSkills/index.mjs +27 -3
- package/dist/esm/installSkills/index.mjs.map +1 -1
- package/dist/esm/listGitFiles.mjs +1 -1
- package/dist/esm/listGitFiles.mjs.map +1 -1
- package/dist/esm/listProjects.mjs +1 -1
- package/dist/esm/listProjects.mjs.map +1 -1
- package/dist/esm/utils/runParallel/pidTree.mjs +3 -3
- package/dist/esm/utils/runParallel/pidTree.mjs.map +1 -1
- package/dist/esm/utils/runParallel/ps.mjs +2 -2
- package/dist/esm/utils/runParallel/ps.mjs.map +1 -1
- package/dist/esm/utils/runParallel/wmic.mjs +2 -2
- package/dist/esm/utils/runParallel/wmic.mjs.map +1 -1
- package/dist/types/cli.d.ts +3 -3
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/init/utils/packageManager.d.ts +5 -0
- package/dist/types/init/utils/packageManager.d.ts.map +1 -1
- package/dist/types/installMCP/installMCP.d.ts +4 -0
- package/dist/types/installMCP/installMCP.d.ts.map +1 -1
- package/dist/types/installSkills/index.d.ts +6 -0
- package/dist/types/installSkills/index.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageManager.cjs","names":["readFileSync","join","existsSync","resolve","dirname","isVersionAtLeast"],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { isVersionAtLeast } from './version';\n\n/** Package managers supported for dependency installation. */\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Configuration for the syncJSON plugin injected into intlayer.config\n * when a compat i18n library is detected.\n */\nexport type CompatSyncConfig = {\n /**\n * Which sync plugin ingests the catalogs:\n * - `'json'` → `syncJSON` from `@intlayer/sync-json-plugin` (default).\n * - `'po'` → `syncPO` from `@intlayer/sync-po-plugin` (lingui's default\n * format).\n */\n plugin?: 'json' | 'po';\n /**\n * JSON format matching the compat library's conventions. Ignored when\n * `plugin` is `'po'` (PO catalogs are always serialized as gettext).\n */\n format: 'icu' | 'i18next' | 'vue-i18n';\n /**\n * Source path template using ${locale} and ${key} placeholders.\n * Rendered as a template literal in the generated config.\n */\n sourceTemplate: string;\n /**\n * Force `splitKeys: true` in the generated `syncJSON(...)` call so each\n * top-level key of a single per-locale file becomes its own dictionary.\n *\n * Set for libraries whose single `messages/${locale}.json` file groups\n * namespaces by its first-level keys (`next-intl` / `use-intl`, where\n * `useTranslations('Hero')` resolves to the `Hero` dictionary). Left\n * undefined for libraries whose top-level keys are plain message keys\n * (e.g. `i18next`, `react-intl`); for those, syncJSON's auto-detection\n * (split only when the source has no `${key}` segment) stays in control.\n *\n * Only meaningful for flat templates (no `${key}` segment); it is dropped\n * automatically when the resolved template addresses one namespace per file.\n */\n splitKeys?: boolean;\n};\n\n/**\n * Configuration for injecting a compat vite plugin into vite.config.\n * The plugin replaces the generic `intlayer` plugin for libraries that\n * require alias injection (e.g. `vue-i18n` → `@intlayer/vue-i18n`).\n */\nexport type CompatVitePluginConfig = {\n /** Exported function name from the plugin package, e.g. `'vueI18nVitePlugin'`. */\n pluginFunctionName: string;\n /** Import path for the plugin package, e.g. `'@intlayer/vue-i18n/plugin'`. */\n pluginPackageSource: string;\n /**\n * Set when the compat plugin is a drop-in replacement for an i18n library's\n * own Vite plugin (e.g. lingui ships `@lingui/vite-plugin`). When the original\n * import is present, init rewrites only that import's module source to\n * `pluginPackageSource` — keeping the binding and its call site — instead of\n * injecting a second import and appending another plugin to the array.\n */\n replacesVitePlugin?: {\n /** Imported binding to keep, e.g. `'lingui'`. */\n importName: string;\n /** Original package source to rewrite, e.g. `'@lingui/vite-plugin'`. */\n fromPackageSource: string;\n };\n};\n\n/** Result of analyzing project dependencies for intlayer package gaps. */\nexport type IntlayerPackageAnalysis = {\n /** Intlayer packages that are referenced but not yet installed. */\n packagesToInstall: string[];\n /** Intlayer dev packages that are referenced but not yet installed. */\n devPackagesToInstall: string[];\n /** Compat packages in dependencies that got replaced and should be moved to devDependencies. */\n packagesToMoveToDev: string[];\n /**\n * syncJSON plugin configuration to inject when a compat i18n library is\n * detected. Undefined when no compat library is present or format is not\n * yet implemented.\n */\n compatSyncConfig: CompatSyncConfig | undefined;\n /**\n * Vite config plugin to inject when a vite-based compat library is\n * detected. Undefined for Next.js/Nuxt-only compat libs or when no compat\n * library requires alias injection.\n */\n compatVitePluginConfig: CompatVitePluginConfig | undefined;\n /**\n * Compat adapters the project would need but that are not published yet\n * (see {@link PENDING_COMPAT_ADAPTERS}). The original library is kept as is;\n * only its catalogs are synced.\n */\n pendingCompatAdapters: string[];\n};\n\n/**\n * Compat adapters that live in `compat-comming/` and are not published to npm\n * yet. Installing one fails the whole install command, so init keeps the\n * original library, skips the adapter and its bundler / framework wiring, and\n * only syncs the catalogs. Remove an entry once its package is released.\n */\nexport const PENDING_COMPAT_ADAPTERS: ReadonlySet<string> = new Set([\n '@intlayer/nuxtjs-i18n',\n '@intlayer/svelte-i18n',\n '@intlayer/ngx-translate',\n]);\n\n/** Lock files revealing the package manager, in detection priority order. */\nconst LOCK_FILE_PACKAGE_MANAGERS: ReadonlyArray<\n readonly [lockFile: string, packageManager: PackageManager]\n> = [\n ['bun.lock', 'bun'],\n ['bun.lockb', 'bun'],\n ['pnpm-lock.yaml', 'pnpm'],\n ['yarn.lock', 'yarn'],\n ['package-lock.json', 'npm'],\n];\n\n/** Package managers accepted in the `packageManager` field of `package.json`. */\nconst PACKAGE_MANAGERS: readonly PackageManager[] = [\n 'bun',\n 'pnpm',\n 'yarn',\n 'npm',\n];\n\n/**\n * Reads the package manager pinned by the `packageManager` field of the\n * `package.json` in `directory` (e.g. `\"pnpm@9.0.0\"`), if any.\n */\nconst readPackageManagerField = (directory: string): PackageManager | null => {\n try {\n const { packageManager } = JSON.parse(\n readFileSync(join(directory, 'package.json'), 'utf8')\n ) as { packageManager?: unknown };\n\n if (typeof packageManager !== 'string') return null;\n\n const name = packageManager.split('@')[0] as PackageManager;\n return PACKAGE_MANAGERS.includes(name) ? name : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root, then the `packageManager` field of its `package.json`. Falls\n * back to npm when neither is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager =>\n LOCK_FILE_PACKAGE_MANAGERS.find(([lockFile]) =>\n existsSync(join(rootDir, lockFile))\n )?.[1] ??\n readPackageManagerField(rootDir) ??\n 'npm';\n\n/**\n * Walks up from `startDir` to the nearest directory holding a lock file — the\n * workspace root an install must run from. Stops at the repository root\n * (`.git`) and returns `null` when no lock file is found.\n */\nexport const findLockFileDir = (startDir: string): string | null => {\n let currentDir = resolve(startDir);\n\n while (true) {\n const hasLockFile = LOCK_FILE_PACKAGE_MANAGERS.some(([lockFile]) =>\n existsSync(join(currentDir, lockFile))\n );\n if (hasLockFile) return currentDir;\n if (existsSync(join(currentDir, '.git'))) return null;\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) return null;\n currentDir = parentDir;\n }\n};\n\n/**\n * Returns the install command for the given package manager and package list.\n */\nconst buildInstallCommand = (\n packageManager: PackageManager,\n packages: string[],\n isDev: boolean = false\n): string => {\n const packageList = packages.join(' ');\n switch (packageManager) {\n case 'bun':\n return `bun add ${isDev ? '-d ' : ''}${packageList}`;\n case 'pnpm':\n return `pnpm add ${isDev ? '-D ' : ''}${packageList}`;\n case 'yarn':\n return `yarn add ${isDev ? '-D ' : ''}${packageList}`;\n case 'npm':\n return `npm install ${isDev ? '-D ' : ''}${packageList}`;\n }\n};\n\n/**\n * Analyzes existing project dependencies to determine which intlayer packages\n * are missing and what syncJSON configuration to inject when compat i18n\n * libraries are present.\n */\n/** Extra signals (from a filesystem scan) that refine compat detection. */\nexport type DetectMissingPackagesOptions = {\n /**\n * Catalog format detected for a lingui project (`'po'` or `'json'`), or\n * `null`/undefined when none was found. Decides which sync plugin + dev\n * dependency the lingui compat setup uses.\n */\n linguiCatalogFormat?: 'po' | 'json' | null;\n /**\n * The project's runtime dependencies (from `package.json` `dependencies`).\n * When provided, compat packages found here that are replaced by `@intlayer/*`\n * are reported in `packagesToMoveToDev`.\n */\n dependencies?: Record<string, string>;\n /**\n * The project's development dependencies (from `package.json` `devDependencies`).\n */\n devDependencies?: Record<string, string>;\n};\n\n/** An existing i18n library Intlayer ships a compat adapter for. */\nexport type CompatI18nLibrary = {\n /** Human-readable name, used to report the detection back to the user. */\n label: string;\n /**\n * Dependency names that reveal the library — both the upstream packages and\n * the Intlayer adapters, so a project that already ran `init` is still\n * recognized.\n */\n packages: readonly string[];\n /**\n * Upstream third-party packages replaced by Intlayer compat adapters at runtime,\n * mapped to their adapter package name.\n */\n replacements: Record<string, string>;\n};\n\n/**\n * Existing i18n libraries Intlayer can adapt, keyed by the dependencies that\n * reveal them. Mirrors the compat branches of\n * {@link detectMissingIntlayerPackages}: a library listed here is one that\n * detection will wire up on its own once its package is in `package.json`.\n */\nexport const COMPAT_I18N_LIBRARIES: readonly CompatI18nLibrary[] = [\n {\n label: 'i18next / react-i18next',\n packages: [\n 'i18next',\n 'react-i18next',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n ],\n replacements: {\n i18next: '@intlayer/i18next',\n 'react-i18next': '@intlayer/react-i18next',\n },\n },\n {\n label: 'next-intl / use-intl',\n packages: [\n 'next-intl',\n 'use-intl',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n ],\n replacements: {\n 'next-intl': '@intlayer/next-intl',\n 'use-intl': '@intlayer/use-intl',\n },\n },\n {\n label: 'vue-i18n',\n packages: ['vue-i18n', '@intlayer/vue-i18n'],\n replacements: {\n 'vue-i18n': '@intlayer/vue-i18n',\n },\n },\n {\n label: '@nuxtjs/i18n',\n packages: ['@nuxtjs/i18n', '@intlayer/nuxtjs-i18n'],\n replacements: {\n '@nuxtjs/i18n': '@intlayer/nuxtjs-i18n',\n },\n },\n {\n label: 'next-i18next',\n packages: ['next-i18next', '@intlayer/next-i18next'],\n replacements: {\n 'next-i18next': '@intlayer/next-i18next',\n },\n },\n {\n label: 'next-translate',\n packages: ['next-translate', '@intlayer/next-translate'],\n replacements: {\n 'next-translate': '@intlayer/next-translate',\n },\n },\n {\n label: 'react-intl',\n packages: ['react-intl', '@intlayer/react-intl'],\n replacements: {\n 'react-intl': '@intlayer/react-intl',\n },\n },\n {\n label: 'Lingui',\n packages: ['@lingui/core', '@lingui/react', '@intlayer/lingui'],\n replacements: {\n '@lingui/core': '@intlayer/lingui',\n '@lingui/react': '@intlayer/lingui',\n },\n },\n {\n label: 'svelte-i18n',\n packages: ['svelte-i18n', '@intlayer/svelte-i18n'],\n replacements: {\n 'svelte-i18n': '@intlayer/svelte-i18n',\n },\n },\n {\n label: '@ngneat/transloco',\n packages: ['@ngneat/transloco', '@intlayer/transloco'],\n replacements: {\n '@ngneat/transloco': '@intlayer/transloco',\n },\n },\n {\n label: '@ngx-translate/core',\n packages: ['@ngx-translate/core', '@intlayer/ngx-translate'],\n replacements: {\n '@ngx-translate/core': '@intlayer/ngx-translate',\n },\n },\n {\n label: 'node-polyglot',\n packages: ['node-polyglot', '@intlayer/polyglot'],\n replacements: {\n 'node-polyglot': '@intlayer/polyglot',\n },\n },\n {\n label: 'i18n-js',\n packages: ['i18n-js', '@intlayer/i18n-js'],\n replacements: {\n 'i18n-js': '@intlayer/i18n-js',\n },\n },\n];\n\n/**\n * Maps third-party i18n libraries to the Intlayer compat adapter that replaces\n * them at runtime, derived from {@link COMPAT_I18N_LIBRARIES}.\n */\nexport const COMPAT_PACKAGE_REPLACEMENTS: Record<string, string> =\n Object.fromEntries(\n COMPAT_I18N_LIBRARIES.flatMap((library) =>\n Object.entries(library.replacements)\n )\n );\n\n/**\n * When a project uses a compat i18n package (such as `next-intl`) that gets\n * replaced by an `@intlayer/*` adapter (e.g. `@intlayer/next-intl`), moves the\n * original package from `dependencies` to `devDependencies` in `package.json`.\n *\n * Returns the list of package names that were moved.\n */\nexport const moveCompatPackagesToDevDependencies = (\n packageJson: Record<string, any>\n): string[] => {\n const movedPackages: string[] = [];\n if (!packageJson.dependencies) return movedPackages;\n\n for (const compatPackage of Object.keys(COMPAT_PACKAGE_REPLACEMENTS)) {\n if (packageJson.dependencies[compatPackage]) {\n const version = packageJson.dependencies[compatPackage];\n delete packageJson.dependencies[compatPackage];\n\n packageJson.devDependencies = packageJson.devDependencies ?? {};\n if (!packageJson.devDependencies[compatPackage]) {\n packageJson.devDependencies[compatPackage] = version;\n }\n movedPackages.push(compatPackage);\n }\n }\n\n return movedPackages;\n};\n\n/**\n * Returns the labels of the compat i18n libraries present in `dependencies`.\n *\n * Lets the init flow report (and branch on) the libraries it found without\n * asking the user, since {@link detectMissingIntlayerPackages} already derives\n * the adapters, sync plugin and config from the very same dependency map.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const detectCompatI18nLibraries = (\n dependencies: Record<string, string>\n): string[] =>\n COMPAT_I18N_LIBRARIES.filter((library) =>\n library.packages.some((packageName) => Boolean(dependencies[packageName]))\n ).map((library) => library.label);\n\n/** Lowest ESLint major `eslint-plugin-intlayer` supports (flat config). */\nexport const MINIMUM_ESLINT_MAJOR = 9;\n\n/**\n * True when the project pins ESLint below {@link MINIMUM_ESLINT_MAJOR}.\n * Installing the plugin there fails on its `eslint` peer range (and takes the\n * whole install command down with it). Ranges without a version number\n * (`latest`, `*`, `catalog:`) are assumed current.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLegacyEslint = (\n dependencies: Record<string, string>\n): boolean => {\n const eslintVersion = dependencies.eslint;\n if (!eslintVersion || !/\\d/.test(eslintVersion)) return false;\n return !isVersionAtLeast(eslintVersion, MINIMUM_ESLINT_MAJOR);\n};\n\n/**\n * True when the project already lints with a linter the Intlayer rules can\n * plug into: oxlint, or ESLint 9+.\n *\n * Shared with the init flow so that installing the plugin and wiring up its\n * configuration are gated on exactly the same condition — a project that does\n * not lint, or lints with ESLint 8, is left alone.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLintTooling = (dependencies: Record<string, string>): boolean =>\n !hasLegacyEslint(dependencies) &&\n (Boolean(dependencies.eslint) || Boolean(dependencies.oxlint));\n\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>,\n options: DetectMissingPackagesOptions = {}\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n const packagesToMoveToDev: string[] = [];\n const pendingCompatAdapters: string[] = [];\n\n let compatSyncConfig: CompatSyncConfig | undefined;\n let compatVitePluginConfig: CompatVitePluginConfig | undefined;\n\n const isInstalled = (packageName: string): boolean =>\n Boolean(allDependencies[packageName]);\n\n const addIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n packagesToInstall.push(packageName);\n }\n };\n\n const addDevIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n devPackagesToInstall.push(packageName);\n }\n };\n\n /**\n * Whether an adapter can be used: published, or already installed by the\n * user (e.g. a local build).\n */\n const isAdapterAvailable = (adapterPackage: string): boolean =>\n !PENDING_COMPAT_ADAPTERS.has(adapterPackage) || isInstalled(adapterPackage);\n\n const markCompatReplacement = (\n originalPackage: string,\n adapterPackage: string\n ): void => {\n if (!isAdapterAvailable(adapterPackage)) {\n if (!pendingCompatAdapters.includes(adapterPackage)) {\n pendingCompatAdapters.push(adapterPackage);\n }\n return;\n }\n\n addIfMissing(adapterPackage);\n addDevIfMissing(originalPackage);\n\n const isExplicitDev = Boolean(options.devDependencies?.[originalPackage]);\n const isExplicitProd = Boolean(options.dependencies?.[originalPackage]);\n const isImplicitProd =\n !options.dependencies &&\n !options.devDependencies &&\n Boolean(allDependencies[originalPackage]);\n\n if ((isExplicitProd || isImplicitProd) && !isExplicitDev) {\n if (!packagesToMoveToDev.includes(originalPackage)) {\n packagesToMoveToDev.push(originalPackage);\n }\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n const isReactNativeProject =\n isInstalled('react-native') || isInstalled('expo');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isReactNativeProject) {\n addIfMissing('react-native-intlayer');\n } else if (isInstalled('react')) {\n addIfMissing('react-intlayer');\n }\n\n if (isInstalled('svelte')) {\n addIfMissing('svelte-intlayer');\n }\n\n if (isInstalled('solid-js')) {\n addIfMissing('solid-intlayer');\n }\n\n if (isInstalled('@angular/core')) {\n addIfMissing('angular-intlayer');\n }\n\n if (isInstalled('vue')) {\n addIfMissing('vue-intlayer');\n }\n\n if (isInstalled('vite')) {\n addIfMissing('vite-intlayer');\n }\n\n // Meta-frameworks whose config init wires the Intlayer module /\n // integration into. A `@nuxtjs/i18n` app keeps its own module instead.\n if (isInstalled('nuxt') && !isInstalled('@nuxtjs/i18n')) {\n addIfMissing('nuxt-intlayer');\n }\n\n if (isInstalled('astro')) {\n addIfMissing('astro-intlayer');\n }\n\n // Server frameworks. NestJS runs on Express unless the Fastify platform is\n // installed, so it gets the matching adapter.\n const isNestJsProject = isInstalled('@nestjs/core');\n const isNestJsOnFastify = isInstalled('@nestjs/platform-fastify');\n\n if (isInstalled('express') || (isNestJsProject && !isNestJsOnFastify)) {\n addIfMissing('express-intlayer');\n }\n\n if (isInstalled('fastify') || isNestJsOnFastify) {\n addIfMissing('fastify-intlayer');\n }\n\n if (isInstalled('hono')) {\n addIfMissing('hono-intlayer');\n }\n\n if (isInstalled('elysia')) {\n addIfMissing('elysia-intlayer');\n }\n\n if (isInstalled('@adonisjs/core')) {\n addIfMissing('adonis-intlayer');\n }\n\n // Lint rules — only when the project already lints.\n if (hasLintTooling(allDependencies)) {\n addDevIfMissing('eslint-plugin-intlayer');\n }\n\n // -------------------------------------------------------------------------\n // Compat adapters for existing i18n libraries.\n //\n // Detection order matters: more specific libraries are checked first so that\n // `compatSyncConfig ??=` and `compatVitePluginConfig ??=` capture the most\n // relevant match. Libraries that only affect the Next.js or Nuxt config do\n // not set `compatVitePluginConfig` (handled separately in init/index.ts).\n // Libraries whose JSON format is not yet supported leave `compatSyncConfig`\n // undefined so no syncJSON plugin is injected.\n // -------------------------------------------------------------------------\n\n // next-intl — next.js only, ICU format. Default layout is a single file per\n // locale (`messages/${locale}.json`) whose top-level keys are namespaces;\n // syncJSON `splitKeys` auto-detection (no `${key}` segment) turns each\n // top-level key into its own dictionary. The exact path is refined from\n // `i18n/request.ts` in init/index.ts when present.\n if (isInstalled('next-intl') || isInstalled('@intlayer/next-intl')) {\n markCompatReplacement('next-intl', '@intlayer/next-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // next-intl groups namespaces by the first-level keys of one file.\n splitKeys: true,\n };\n // next config handled via updateNextConfigForNextIntl in init/index.ts\n }\n\n // next-i18next — next.js only, i18next JSON format\n if (isInstalled('next-i18next') || isInstalled('@intlayer/next-i18next')) {\n markCompatReplacement('next-i18next', '@intlayer/next-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextI18next in init/index.ts\n }\n\n // next-translate — next.js only, i18next-style flat-namespace JSON\n if (\n isInstalled('next-translate') ||\n isInstalled('@intlayer/next-translate')\n ) {\n markCompatReplacement('next-translate', '@intlayer/next-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextTranslate in init/index.ts\n }\n\n // i18next — vite alias injection (`i18next` → `@intlayer/i18next`) so existing\n // `import … from 'i18next'` is served by Intlayer without touching call sites.\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n markCompatReplacement('i18next', '@intlayer/i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // When react-i18next is also present, its wrapper plugin aliases both\n // `react-i18next` and `i18next`, so it must win — only inject the bare\n // i18next plugin when no React wrapper is installed.\n if (\n !isInstalled('react-i18next') &&\n !isInstalled('@intlayer/react-i18next')\n ) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nextVitePlugin',\n pluginPackageSource: '@intlayer/i18next/plugin',\n };\n }\n }\n\n // react-i18next — vite alias injection (`react-i18next` → `@intlayer/react-i18next`\n // and `i18next` → `@intlayer/i18next`) so components keep importing from\n // `react-i18next` unchanged.\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n markCompatReplacement('react-i18next', '@intlayer/react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactI18nextVitePlugin',\n pluginPackageSource: '@intlayer/react-i18next/plugin',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n markCompatReplacement('vue-i18n', '@intlayer/vue-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'vueI18nVitePlugin',\n pluginPackageSource: '@intlayer/vue-i18n/plugin',\n };\n }\n\n // use-intl — framework-agnostic React core of next-intl; vite alias\n // injection required, ICU format. Commonly a single `messages/${locale}.json`\n // file whose top-level keys are namespaces, handled by syncJSON `splitKeys`\n // auto-detection (no `${key}` segment in the source template).\n if (isInstalled('use-intl') || isInstalled('@intlayer/use-intl')) {\n markCompatReplacement('use-intl', '@intlayer/use-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // use-intl (the core of next-intl) uses the same single-file namespace model.\n splitKeys: true,\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'useIntlVitePlugin',\n pluginPackageSource: '@intlayer/use-intl/plugin',\n };\n }\n\n // react-intl — vite alias injection required, ICU format\n if (isInstalled('react-intl') || isInstalled('@intlayer/react-intl')) {\n markCompatReplacement('react-intl', '@intlayer/react-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './src/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactIntlVitePlugin',\n pluginPackageSource: '@intlayer/react-intl/plugin',\n };\n }\n\n // @ngneat/transloco — vite alias injection required\n // @todo syncJSON format not yet implemented for transloco\n if (isInstalled('@ngneat/transloco') || isInstalled('@intlayer/transloco')) {\n markCompatReplacement('@ngneat/transloco', '@intlayer/transloco');\n if (isAdapterAvailable('@intlayer/transloco')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n markCompatReplacement('svelte-i18n', '@intlayer/svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/svelte-i18n')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\n }\n }\n\n // node-polyglot — vite alias injection required\n // @todo syncJSON format not yet implemented for polyglot\n if (isInstalled('node-polyglot') || isInstalled('@intlayer/polyglot')) {\n markCompatReplacement('node-polyglot', '@intlayer/polyglot');\n if (isAdapterAvailable('@intlayer/polyglot')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\n }\n }\n\n // @nuxtjs/i18n — nuxt module (no vite plugin), vue-i18n JSON format\n if (isInstalled('@nuxtjs/i18n') || isInstalled('@intlayer/nuxtjs-i18n')) {\n markCompatReplacement('@nuxtjs/i18n', '@intlayer/nuxtjs-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // nuxt config handled via updateNuxtConfigForNuxtjsI18n in init/index.ts\n }\n\n // @ngx-translate/core — vite alias injection required, flat JSON (i18next)\n if (\n isInstalled('@ngx-translate/core') ||\n isInstalled('@intlayer/ngx-translate')\n ) {\n markCompatReplacement('@ngx-translate/core', '@intlayer/ngx-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/ngx-translate')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n }\n\n // @lingui/core — vite alias injection required.\n // lingui keeps one catalog file per locale (default name `messages`), as\n // `.po` (its default) or `.json`. The catalog filename is captured by the\n // `${key}` segment so the produced dictionary key is `messages`, matching the\n // fixed `messages` namespace the lingui compat runtime reads from.\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n markCompatReplacement('@lingui/core', '@intlayer/lingui');\n\n if (isInstalled('@lingui/react')) {\n markCompatReplacement('@lingui/react', '@intlayer/lingui');\n }\n\n const linguiUsesPo = options.linguiCatalogFormat === 'po';\n compatSyncConfig ??= linguiUsesPo\n ? {\n plugin: 'po',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.po',\n }\n : {\n plugin: 'json',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n\n compatVitePluginConfig ??= {\n // `@intlayer/lingui/plugin` exports `lingui` as a drop-in replacement for\n // `@lingui/vite-plugin`, so a fresh project gets `lingui()` injected and a\n // project already using `@lingui/vite-plugin` only has its import source\n // rewritten (see `replacesVitePlugin`).\n pluginFunctionName: 'lingui',\n pluginPackageSource: '@intlayer/lingui/plugin',\n replacesVitePlugin: {\n importName: 'lingui',\n fromPackageSource: '@lingui/vite-plugin',\n },\n };\n }\n\n // i18n-js — vite alias injection required\n // @todo syncJSON format not yet implemented for i18n-js\n if (isInstalled('i18n-js') || isInstalled('@intlayer/i18n-js')) {\n markCompatReplacement('i18n-js', '@intlayer/i18n-js');\n if (isAdapterAvailable('@intlayer/i18n-js')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n }\n\n if (compatSyncConfig) {\n addDevIfMissing(\n compatSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin'\n );\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n packagesToMoveToDev,\n compatSyncConfig,\n compatVitePluginConfig,\n pendingCompatAdapters,\n };\n};\n\n/**\n * Runs the package install command synchronously.\n * Throws if the install process exits with a non-zero code.\n */\nexport const installPackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n isDev: boolean = false\n): void => {\n const command = buildInstallCommand(packageManager, packages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n\n/**\n * Determines whether a dependency name belongs to the Intlayer ecosystem.\n *\n * Matches the core `intlayer` package, every scoped `@intlayer/*` package\n * (including compat adapters such as `@intlayer/next-intl`) and the framework\n * runtime integrations that follow the `<framework>-intlayer` convention\n * (e.g. `next-intlayer`, `react-intlayer`, `express-intlayer`), as well as the\n * `intlayer-*` packages (e.g. `intlayer-editor`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n packageName.startsWith('intlayer-') ||\n packageName.endsWith('-intlayer');\n\n/**\n * Reduces a semver range or full version to its `major.minor.patch` core,\n * stripping range prefixes (`^`, `~`), pre-release identifiers and build\n * metadata. Returns `null` when no `major.minor.patch` can be extracted.\n *\n * @example normalizeVersion('^9.0.0-canary.3') // '9.0.0'\n */\nexport const normalizeVersion = (version?: string): string | null => {\n if (!version || typeof version !== 'string') return null;\n\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Runs the package manager install command synchronously, so edited\n * `package.json` ranges are resolved and the lock file updated. Throws if the\n * install process exits with a non-zero code.\n */\nexport const runPackageInstall = (\n rootDir: string,\n packageManager: PackageManager\n): void => {\n execSync(`${packageManager} install`, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"packageManager.cjs","names":["readFileSync","join","existsSync","resolve","dirname","isVersionAtLeast"],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { isVersionAtLeast } from './version';\n\n/** Package managers supported for dependency installation. */\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Configuration for the syncJSON plugin injected into intlayer.config\n * when a compat i18n library is detected.\n */\nexport type CompatSyncConfig = {\n /**\n * Which sync plugin ingests the catalogs:\n * - `'json'` → `syncJSON` from `@intlayer/sync-json-plugin` (default).\n * - `'po'` → `syncPO` from `@intlayer/sync-po-plugin` (lingui's default\n * format).\n */\n plugin?: 'json' | 'po';\n /**\n * JSON format matching the compat library's conventions. Ignored when\n * `plugin` is `'po'` (PO catalogs are always serialized as gettext).\n */\n format: 'icu' | 'i18next' | 'vue-i18n';\n /**\n * Source path template using ${locale} and ${key} placeholders.\n * Rendered as a template literal in the generated config.\n */\n sourceTemplate: string;\n /**\n * Force `splitKeys: true` in the generated `syncJSON(...)` call so each\n * top-level key of a single per-locale file becomes its own dictionary.\n *\n * Set for libraries whose single `messages/${locale}.json` file groups\n * namespaces by its first-level keys (`next-intl` / `use-intl`, where\n * `useTranslations('Hero')` resolves to the `Hero` dictionary). Left\n * undefined for libraries whose top-level keys are plain message keys\n * (e.g. `i18next`, `react-intl`); for those, syncJSON's auto-detection\n * (split only when the source has no `${key}` segment) stays in control.\n *\n * Only meaningful for flat templates (no `${key}` segment); it is dropped\n * automatically when the resolved template addresses one namespace per file.\n */\n splitKeys?: boolean;\n};\n\n/**\n * Configuration for injecting a compat vite plugin into vite.config.\n * The plugin replaces the generic `intlayer` plugin for libraries that\n * require alias injection (e.g. `vue-i18n` → `@intlayer/vue-i18n`).\n */\nexport type CompatVitePluginConfig = {\n /** Exported function name from the plugin package, e.g. `'vueI18nVitePlugin'`. */\n pluginFunctionName: string;\n /** Import path for the plugin package, e.g. `'@intlayer/vue-i18n/plugin'`. */\n pluginPackageSource: string;\n /**\n * Set when the compat plugin is a drop-in replacement for an i18n library's\n * own Vite plugin (e.g. lingui ships `@lingui/vite-plugin`). When the original\n * import is present, init rewrites only that import's module source to\n * `pluginPackageSource` — keeping the binding and its call site — instead of\n * injecting a second import and appending another plugin to the array.\n */\n replacesVitePlugin?: {\n /** Imported binding to keep, e.g. `'lingui'`. */\n importName: string;\n /** Original package source to rewrite, e.g. `'@lingui/vite-plugin'`. */\n fromPackageSource: string;\n };\n};\n\n/** Result of analyzing project dependencies for intlayer package gaps. */\nexport type IntlayerPackageAnalysis = {\n /** Intlayer packages that are referenced but not yet installed. */\n packagesToInstall: string[];\n /** Intlayer dev packages that are referenced but not yet installed. */\n devPackagesToInstall: string[];\n /** Compat packages in dependencies that got replaced and should be moved to devDependencies. */\n packagesToMoveToDev: string[];\n /**\n * syncJSON plugin configuration to inject when a compat i18n library is\n * detected. Undefined when no compat library is present or format is not\n * yet implemented.\n */\n compatSyncConfig: CompatSyncConfig | undefined;\n /**\n * Vite config plugin to inject when a vite-based compat library is\n * detected. Undefined for Next.js/Nuxt-only compat libs or when no compat\n * library requires alias injection.\n */\n compatVitePluginConfig: CompatVitePluginConfig | undefined;\n /**\n * Compat adapters the project would need but that are not published yet\n * (see {@link PENDING_COMPAT_ADAPTERS}). The original library is kept as is;\n * only its catalogs are synced.\n */\n pendingCompatAdapters: string[];\n};\n\n/**\n * Compat adapters that live in `compat-comming/` and are not published to npm\n * yet. Installing one fails the whole install command, so init keeps the\n * original library, skips the adapter and its bundler / framework wiring, and\n * only syncs the catalogs. Remove an entry once its package is released.\n */\nexport const PENDING_COMPAT_ADAPTERS: ReadonlySet<string> = new Set([\n '@intlayer/nuxtjs-i18n',\n '@intlayer/svelte-i18n',\n '@intlayer/ngx-translate',\n]);\n\n/** Lock files revealing the package manager, in detection priority order. */\nconst LOCK_FILE_PACKAGE_MANAGERS: ReadonlyArray<\n readonly [lockFile: string, packageManager: PackageManager]\n> = [\n ['bun.lock', 'bun'],\n ['bun.lockb', 'bun'],\n ['pnpm-lock.yaml', 'pnpm'],\n ['yarn.lock', 'yarn'],\n ['package-lock.json', 'npm'],\n];\n\n/** Package managers accepted in the `packageManager` field of `package.json`. */\nconst PACKAGE_MANAGERS: readonly PackageManager[] = [\n 'bun',\n 'pnpm',\n 'yarn',\n 'npm',\n];\n\n/**\n * Reads the package manager pinned by the `packageManager` field of the\n * `package.json` in `directory` (e.g. `\"pnpm@9.0.0\"`), if any.\n */\nconst readPackageManagerField = (directory: string): PackageManager | null => {\n try {\n const { packageManager } = JSON.parse(\n readFileSync(join(directory, 'package.json'), 'utf8')\n ) as { packageManager?: unknown };\n\n if (typeof packageManager !== 'string') return null;\n\n const name = packageManager.split('@')[0] as PackageManager;\n return PACKAGE_MANAGERS.includes(name) ? name : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root, then the `packageManager` field of its `package.json`. Falls\n * back to npm when neither is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager =>\n LOCK_FILE_PACKAGE_MANAGERS.find(([lockFile]) =>\n existsSync(join(rootDir, lockFile))\n )?.[1] ??\n readPackageManagerField(rootDir) ??\n 'npm';\n\n/**\n * Walks up from `startDir` to the nearest directory holding a lock file — the\n * workspace root an install must run from. Stops at the repository root\n * (`.git`) and returns `null` when no lock file is found.\n */\nexport const findLockFileDir = (startDir: string): string | null => {\n let currentDir = resolve(startDir);\n\n while (true) {\n const hasLockFile = LOCK_FILE_PACKAGE_MANAGERS.some(([lockFile]) =>\n existsSync(join(currentDir, lockFile))\n );\n if (hasLockFile) return currentDir;\n if (existsSync(join(currentDir, '.git'))) return null;\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) return null;\n currentDir = parentDir;\n }\n};\n\n/**\n * Returns the install command for the given package manager and package list.\n */\nconst buildInstallCommand = (\n packageManager: PackageManager,\n packages: string[],\n isDev: boolean = false\n): string => {\n const packageList = packages.join(' ');\n switch (packageManager) {\n case 'bun':\n return `bun add ${isDev ? '-d ' : ''}${packageList}`;\n case 'pnpm':\n return `pnpm add ${isDev ? '-D ' : ''}${packageList}`;\n case 'yarn':\n return `yarn add ${isDev ? '-D ' : ''}${packageList}`;\n case 'npm':\n return `npm install ${isDev ? '-D ' : ''}${packageList}`;\n }\n};\n\n/**\n * Analyzes existing project dependencies to determine which intlayer packages\n * are missing and what syncJSON configuration to inject when compat i18n\n * libraries are present.\n */\n/** Extra signals (from a filesystem scan) that refine compat detection. */\nexport type DetectMissingPackagesOptions = {\n /**\n * Catalog format detected for a lingui project (`'po'` or `'json'`), or\n * `null`/undefined when none was found. Decides which sync plugin + dev\n * dependency the lingui compat setup uses.\n */\n linguiCatalogFormat?: 'po' | 'json' | null;\n /**\n * The project's runtime dependencies (from `package.json` `dependencies`).\n * When provided, compat packages found here that are replaced by `@intlayer/*`\n * are reported in `packagesToMoveToDev`.\n */\n dependencies?: Record<string, string>;\n /**\n * The project's development dependencies (from `package.json` `devDependencies`).\n */\n devDependencies?: Record<string, string>;\n /**\n * Skip `eslint-plugin-intlayer`, even when the project lints. Set when the\n * lint step is not part of the setup.\n */\n skipLintPlugin?: boolean;\n};\n\n/** An existing i18n library Intlayer ships a compat adapter for. */\nexport type CompatI18nLibrary = {\n /** Human-readable name, used to report the detection back to the user. */\n label: string;\n /**\n * Dependency names that reveal the library — both the upstream packages and\n * the Intlayer adapters, so a project that already ran `init` is still\n * recognized.\n */\n packages: readonly string[];\n /**\n * Upstream third-party packages replaced by Intlayer compat adapters at runtime,\n * mapped to their adapter package name.\n */\n replacements: Record<string, string>;\n};\n\n/**\n * Existing i18n libraries Intlayer can adapt, keyed by the dependencies that\n * reveal them. Mirrors the compat branches of\n * {@link detectMissingIntlayerPackages}: a library listed here is one that\n * detection will wire up on its own once its package is in `package.json`.\n */\nexport const COMPAT_I18N_LIBRARIES: readonly CompatI18nLibrary[] = [\n {\n label: 'i18next / react-i18next',\n packages: [\n 'i18next',\n 'react-i18next',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n ],\n replacements: {\n i18next: '@intlayer/i18next',\n 'react-i18next': '@intlayer/react-i18next',\n },\n },\n {\n label: 'next-intl / use-intl',\n packages: [\n 'next-intl',\n 'use-intl',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n ],\n replacements: {\n 'next-intl': '@intlayer/next-intl',\n 'use-intl': '@intlayer/use-intl',\n },\n },\n {\n label: 'vue-i18n',\n packages: ['vue-i18n', '@intlayer/vue-i18n'],\n replacements: {\n 'vue-i18n': '@intlayer/vue-i18n',\n },\n },\n {\n label: '@nuxtjs/i18n',\n packages: ['@nuxtjs/i18n', '@intlayer/nuxtjs-i18n'],\n replacements: {\n '@nuxtjs/i18n': '@intlayer/nuxtjs-i18n',\n },\n },\n {\n label: 'next-i18next',\n packages: ['next-i18next', '@intlayer/next-i18next'],\n replacements: {\n 'next-i18next': '@intlayer/next-i18next',\n },\n },\n {\n label: 'next-translate',\n packages: ['next-translate', '@intlayer/next-translate'],\n replacements: {\n 'next-translate': '@intlayer/next-translate',\n },\n },\n {\n label: 'react-intl',\n packages: ['react-intl', '@intlayer/react-intl'],\n replacements: {\n 'react-intl': '@intlayer/react-intl',\n },\n },\n {\n label: 'Lingui',\n packages: ['@lingui/core', '@lingui/react', '@intlayer/lingui'],\n replacements: {\n '@lingui/core': '@intlayer/lingui',\n '@lingui/react': '@intlayer/lingui',\n },\n },\n {\n label: 'svelte-i18n',\n packages: ['svelte-i18n', '@intlayer/svelte-i18n'],\n replacements: {\n 'svelte-i18n': '@intlayer/svelte-i18n',\n },\n },\n {\n label: '@ngneat/transloco',\n packages: ['@ngneat/transloco', '@intlayer/transloco'],\n replacements: {\n '@ngneat/transloco': '@intlayer/transloco',\n },\n },\n {\n label: '@ngx-translate/core',\n packages: ['@ngx-translate/core', '@intlayer/ngx-translate'],\n replacements: {\n '@ngx-translate/core': '@intlayer/ngx-translate',\n },\n },\n {\n label: 'node-polyglot',\n packages: ['node-polyglot', '@intlayer/polyglot'],\n replacements: {\n 'node-polyglot': '@intlayer/polyglot',\n },\n },\n {\n label: 'i18n-js',\n packages: ['i18n-js', '@intlayer/i18n-js'],\n replacements: {\n 'i18n-js': '@intlayer/i18n-js',\n },\n },\n];\n\n/**\n * Maps third-party i18n libraries to the Intlayer compat adapter that replaces\n * them at runtime, derived from {@link COMPAT_I18N_LIBRARIES}.\n */\nexport const COMPAT_PACKAGE_REPLACEMENTS: Record<string, string> =\n Object.fromEntries(\n COMPAT_I18N_LIBRARIES.flatMap((library) =>\n Object.entries(library.replacements)\n )\n );\n\n/**\n * When a project uses a compat i18n package (such as `next-intl`) that gets\n * replaced by an `@intlayer/*` adapter (e.g. `@intlayer/next-intl`), moves the\n * original package from `dependencies` to `devDependencies` in `package.json`.\n *\n * Returns the list of package names that were moved.\n */\nexport const moveCompatPackagesToDevDependencies = (\n packageJson: Record<string, any>\n): string[] => {\n const movedPackages: string[] = [];\n if (!packageJson.dependencies) return movedPackages;\n\n for (const compatPackage of Object.keys(COMPAT_PACKAGE_REPLACEMENTS)) {\n if (packageJson.dependencies[compatPackage]) {\n const version = packageJson.dependencies[compatPackage];\n delete packageJson.dependencies[compatPackage];\n\n packageJson.devDependencies = packageJson.devDependencies ?? {};\n if (!packageJson.devDependencies[compatPackage]) {\n packageJson.devDependencies[compatPackage] = version;\n }\n movedPackages.push(compatPackage);\n }\n }\n\n return movedPackages;\n};\n\n/**\n * Returns the labels of the compat i18n libraries present in `dependencies`.\n *\n * Lets the init flow report (and branch on) the libraries it found without\n * asking the user, since {@link detectMissingIntlayerPackages} already derives\n * the adapters, sync plugin and config from the very same dependency map.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const detectCompatI18nLibraries = (\n dependencies: Record<string, string>\n): string[] =>\n COMPAT_I18N_LIBRARIES.filter((library) =>\n library.packages.some((packageName) => Boolean(dependencies[packageName]))\n ).map((library) => library.label);\n\n/** Lowest ESLint major `eslint-plugin-intlayer` supports (flat config). */\nexport const MINIMUM_ESLINT_MAJOR = 9;\n\n/**\n * True when the project pins ESLint below {@link MINIMUM_ESLINT_MAJOR}.\n * Installing the plugin there fails on its `eslint` peer range (and takes the\n * whole install command down with it). Ranges without a version number\n * (`latest`, `*`, `catalog:`) are assumed current.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLegacyEslint = (\n dependencies: Record<string, string>\n): boolean => {\n const eslintVersion = dependencies.eslint;\n if (!eslintVersion || !/\\d/.test(eslintVersion)) return false;\n return !isVersionAtLeast(eslintVersion, MINIMUM_ESLINT_MAJOR);\n};\n\n/**\n * True when the project already lints with a linter the Intlayer rules can\n * plug into: oxlint, or ESLint 9+.\n *\n * Shared with the init flow so that installing the plugin and wiring up its\n * configuration are gated on exactly the same condition — a project that does\n * not lint, or lints with ESLint 8, is left alone.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLintTooling = (dependencies: Record<string, string>): boolean =>\n !hasLegacyEslint(dependencies) &&\n (Boolean(dependencies.eslint) || Boolean(dependencies.oxlint));\n\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>,\n options: DetectMissingPackagesOptions = {}\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n const packagesToMoveToDev: string[] = [];\n const pendingCompatAdapters: string[] = [];\n\n let compatSyncConfig: CompatSyncConfig | undefined;\n let compatVitePluginConfig: CompatVitePluginConfig | undefined;\n\n const isInstalled = (packageName: string): boolean =>\n Boolean(allDependencies[packageName]);\n\n const addIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n packagesToInstall.push(packageName);\n }\n };\n\n const addDevIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n devPackagesToInstall.push(packageName);\n }\n };\n\n /**\n * Whether an adapter can be used: published, or already installed by the\n * user (e.g. a local build).\n */\n const isAdapterAvailable = (adapterPackage: string): boolean =>\n !PENDING_COMPAT_ADAPTERS.has(adapterPackage) || isInstalled(adapterPackage);\n\n const markCompatReplacement = (\n originalPackage: string,\n adapterPackage: string\n ): void => {\n if (!isAdapterAvailable(adapterPackage)) {\n if (!pendingCompatAdapters.includes(adapterPackage)) {\n pendingCompatAdapters.push(adapterPackage);\n }\n return;\n }\n\n addIfMissing(adapterPackage);\n addDevIfMissing(originalPackage);\n\n const isExplicitDev = Boolean(options.devDependencies?.[originalPackage]);\n const isExplicitProd = Boolean(options.dependencies?.[originalPackage]);\n const isImplicitProd =\n !options.dependencies &&\n !options.devDependencies &&\n Boolean(allDependencies[originalPackage]);\n\n if ((isExplicitProd || isImplicitProd) && !isExplicitDev) {\n if (!packagesToMoveToDev.includes(originalPackage)) {\n packagesToMoveToDev.push(originalPackage);\n }\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n const isReactNativeProject =\n isInstalled('react-native') || isInstalled('expo');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isReactNativeProject) {\n addIfMissing('react-native-intlayer');\n } else if (isInstalled('react')) {\n addIfMissing('react-intlayer');\n }\n\n if (isInstalled('svelte')) {\n addIfMissing('svelte-intlayer');\n }\n\n if (isInstalled('solid-js')) {\n addIfMissing('solid-intlayer');\n }\n\n if (isInstalled('@angular/core')) {\n addIfMissing('angular-intlayer');\n }\n\n if (isInstalled('vue')) {\n addIfMissing('vue-intlayer');\n }\n\n if (isInstalled('vite')) {\n addIfMissing('vite-intlayer');\n }\n\n // Meta-frameworks whose config init wires the Intlayer module /\n // integration into. A `@nuxtjs/i18n` app keeps its own module instead.\n if (isInstalled('nuxt') && !isInstalled('@nuxtjs/i18n')) {\n addIfMissing('nuxt-intlayer');\n }\n\n if (isInstalled('astro')) {\n addIfMissing('astro-intlayer');\n }\n\n // Server frameworks. NestJS runs on Express unless the Fastify platform is\n // installed, so it gets the matching adapter.\n const isNestJsProject = isInstalled('@nestjs/core');\n const isNestJsOnFastify = isInstalled('@nestjs/platform-fastify');\n\n if (isInstalled('express') || (isNestJsProject && !isNestJsOnFastify)) {\n addIfMissing('express-intlayer');\n }\n\n if (isInstalled('fastify') || isNestJsOnFastify) {\n addIfMissing('fastify-intlayer');\n }\n\n if (isInstalled('hono')) {\n addIfMissing('hono-intlayer');\n }\n\n if (isInstalled('elysia')) {\n addIfMissing('elysia-intlayer');\n }\n\n if (isInstalled('@adonisjs/core')) {\n addIfMissing('adonis-intlayer');\n }\n\n // Lint rules — only when the project already lints.\n if (!options.skipLintPlugin && hasLintTooling(allDependencies)) {\n addDevIfMissing('eslint-plugin-intlayer');\n }\n\n // -------------------------------------------------------------------------\n // Compat adapters for existing i18n libraries.\n //\n // Detection order matters: more specific libraries are checked first so that\n // `compatSyncConfig ??=` and `compatVitePluginConfig ??=` capture the most\n // relevant match. Libraries that only affect the Next.js or Nuxt config do\n // not set `compatVitePluginConfig` (handled separately in init/index.ts).\n // Libraries whose JSON format is not yet supported leave `compatSyncConfig`\n // undefined so no syncJSON plugin is injected.\n // -------------------------------------------------------------------------\n\n // next-intl — next.js only, ICU format. Default layout is a single file per\n // locale (`messages/${locale}.json`) whose top-level keys are namespaces;\n // syncJSON `splitKeys` auto-detection (no `${key}` segment) turns each\n // top-level key into its own dictionary. The exact path is refined from\n // `i18n/request.ts` in init/index.ts when present.\n if (isInstalled('next-intl') || isInstalled('@intlayer/next-intl')) {\n markCompatReplacement('next-intl', '@intlayer/next-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // next-intl groups namespaces by the first-level keys of one file.\n splitKeys: true,\n };\n // next config handled via updateNextConfigForNextIntl in init/index.ts\n }\n\n // next-i18next — next.js only, i18next JSON format\n if (isInstalled('next-i18next') || isInstalled('@intlayer/next-i18next')) {\n markCompatReplacement('next-i18next', '@intlayer/next-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextI18next in init/index.ts\n }\n\n // next-translate — next.js only, i18next-style flat-namespace JSON\n if (\n isInstalled('next-translate') ||\n isInstalled('@intlayer/next-translate')\n ) {\n markCompatReplacement('next-translate', '@intlayer/next-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextTranslate in init/index.ts\n }\n\n // i18next — vite alias injection (`i18next` → `@intlayer/i18next`) so existing\n // `import … from 'i18next'` is served by Intlayer without touching call sites.\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n markCompatReplacement('i18next', '@intlayer/i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // When react-i18next is also present, its wrapper plugin aliases both\n // `react-i18next` and `i18next`, so it must win — only inject the bare\n // i18next plugin when no React wrapper is installed.\n if (\n !isInstalled('react-i18next') &&\n !isInstalled('@intlayer/react-i18next')\n ) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nextVitePlugin',\n pluginPackageSource: '@intlayer/i18next/plugin',\n };\n }\n }\n\n // react-i18next — vite alias injection (`react-i18next` → `@intlayer/react-i18next`\n // and `i18next` → `@intlayer/i18next`) so components keep importing from\n // `react-i18next` unchanged.\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n markCompatReplacement('react-i18next', '@intlayer/react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactI18nextVitePlugin',\n pluginPackageSource: '@intlayer/react-i18next/plugin',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n markCompatReplacement('vue-i18n', '@intlayer/vue-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'vueI18nVitePlugin',\n pluginPackageSource: '@intlayer/vue-i18n/plugin',\n };\n }\n\n // use-intl — framework-agnostic React core of next-intl; vite alias\n // injection required, ICU format. Commonly a single `messages/${locale}.json`\n // file whose top-level keys are namespaces, handled by syncJSON `splitKeys`\n // auto-detection (no `${key}` segment in the source template).\n if (isInstalled('use-intl') || isInstalled('@intlayer/use-intl')) {\n markCompatReplacement('use-intl', '@intlayer/use-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // use-intl (the core of next-intl) uses the same single-file namespace model.\n splitKeys: true,\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'useIntlVitePlugin',\n pluginPackageSource: '@intlayer/use-intl/plugin',\n };\n }\n\n // react-intl — vite alias injection required, ICU format\n if (isInstalled('react-intl') || isInstalled('@intlayer/react-intl')) {\n markCompatReplacement('react-intl', '@intlayer/react-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './src/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactIntlVitePlugin',\n pluginPackageSource: '@intlayer/react-intl/plugin',\n };\n }\n\n // @ngneat/transloco — vite alias injection required\n // @todo syncJSON format not yet implemented for transloco\n if (isInstalled('@ngneat/transloco') || isInstalled('@intlayer/transloco')) {\n markCompatReplacement('@ngneat/transloco', '@intlayer/transloco');\n if (isAdapterAvailable('@intlayer/transloco')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n markCompatReplacement('svelte-i18n', '@intlayer/svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/svelte-i18n')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\n }\n }\n\n // node-polyglot — vite alias injection required\n // @todo syncJSON format not yet implemented for polyglot\n if (isInstalled('node-polyglot') || isInstalled('@intlayer/polyglot')) {\n markCompatReplacement('node-polyglot', '@intlayer/polyglot');\n if (isAdapterAvailable('@intlayer/polyglot')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\n }\n }\n\n // @nuxtjs/i18n — nuxt module (no vite plugin), vue-i18n JSON format\n if (isInstalled('@nuxtjs/i18n') || isInstalled('@intlayer/nuxtjs-i18n')) {\n markCompatReplacement('@nuxtjs/i18n', '@intlayer/nuxtjs-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // nuxt config handled via updateNuxtConfigForNuxtjsI18n in init/index.ts\n }\n\n // @ngx-translate/core — vite alias injection required, flat JSON (i18next)\n if (\n isInstalled('@ngx-translate/core') ||\n isInstalled('@intlayer/ngx-translate')\n ) {\n markCompatReplacement('@ngx-translate/core', '@intlayer/ngx-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/ngx-translate')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n }\n\n // @lingui/core — vite alias injection required.\n // lingui keeps one catalog file per locale (default name `messages`), as\n // `.po` (its default) or `.json`. The catalog filename is captured by the\n // `${key}` segment so the produced dictionary key is `messages`, matching the\n // fixed `messages` namespace the lingui compat runtime reads from.\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n markCompatReplacement('@lingui/core', '@intlayer/lingui');\n\n if (isInstalled('@lingui/react')) {\n markCompatReplacement('@lingui/react', '@intlayer/lingui');\n }\n\n const linguiUsesPo = options.linguiCatalogFormat === 'po';\n compatSyncConfig ??= linguiUsesPo\n ? {\n plugin: 'po',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.po',\n }\n : {\n plugin: 'json',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n\n compatVitePluginConfig ??= {\n // `@intlayer/lingui/plugin` exports `lingui` as a drop-in replacement for\n // `@lingui/vite-plugin`, so a fresh project gets `lingui()` injected and a\n // project already using `@lingui/vite-plugin` only has its import source\n // rewritten (see `replacesVitePlugin`).\n pluginFunctionName: 'lingui',\n pluginPackageSource: '@intlayer/lingui/plugin',\n replacesVitePlugin: {\n importName: 'lingui',\n fromPackageSource: '@lingui/vite-plugin',\n },\n };\n }\n\n // i18n-js — vite alias injection required\n // @todo syncJSON format not yet implemented for i18n-js\n if (isInstalled('i18n-js') || isInstalled('@intlayer/i18n-js')) {\n markCompatReplacement('i18n-js', '@intlayer/i18n-js');\n if (isAdapterAvailable('@intlayer/i18n-js')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n }\n\n if (compatSyncConfig) {\n addDevIfMissing(\n compatSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin'\n );\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n packagesToMoveToDev,\n compatSyncConfig,\n compatVitePluginConfig,\n pendingCompatAdapters,\n };\n};\n\n/**\n * Runs the package install command synchronously.\n * Throws if the install process exits with a non-zero code.\n */\nexport const installPackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n isDev: boolean = false\n): void => {\n const command = buildInstallCommand(packageManager, packages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n\n/**\n * Determines whether a dependency name belongs to the Intlayer ecosystem.\n *\n * Matches the core `intlayer` package, every scoped `@intlayer/*` package\n * (including compat adapters such as `@intlayer/next-intl`) and the framework\n * runtime integrations that follow the `<framework>-intlayer` convention\n * (e.g. `next-intlayer`, `react-intlayer`, `express-intlayer`), as well as the\n * `intlayer-*` packages (e.g. `intlayer-editor`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n packageName.startsWith('intlayer-') ||\n packageName.endsWith('-intlayer');\n\n/**\n * Reduces a semver range or full version to its `major.minor.patch` core,\n * stripping range prefixes (`^`, `~`), pre-release identifiers and build\n * metadata. Returns `null` when no `major.minor.patch` can be extracted.\n *\n * @example normalizeVersion('^9.0.0-canary.3') // '9.0.0'\n */\nexport const normalizeVersion = (version?: string): string | null => {\n if (!version || typeof version !== 'string') return null;\n\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Runs the package manager install command synchronously, so edited\n * `package.json` ranges are resolved and the lock file updated. Throws if the\n * install process exits with a non-zero code.\n */\nexport const runPackageInstall = (\n rootDir: string,\n packageManager: PackageManager\n): void => {\n execSync(`${packageManager} install`, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
|
|
@@ -4,48 +4,58 @@ const require_installSkills_index = require('../installSkills/index.cjs');
|
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
node_path = require_runtime.__toESM(node_path);
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
|
-
let node_os = require("node:os");
|
|
8
|
-
node_os = require_runtime.__toESM(node_os);
|
|
9
7
|
|
|
10
8
|
//#region src/installMCP/installMCP.ts
|
|
9
|
+
/** Transports accepted by `intlayer init mcp --transport`. */
|
|
10
|
+
const MCP_TRANSPORTS = ["stdio", "sse"];
|
|
11
11
|
const MCP_CONFIG_FILENAME = "mcp.json";
|
|
12
|
-
|
|
12
|
+
/** Project-scoped MCP configuration file read by Claude Code. */
|
|
13
|
+
const CLAUDE_CODE_MCP_CONFIG_FILENAME = ".mcp.json";
|
|
14
|
+
/** Platforms whose MCP entries declare their transport as `type`. */
|
|
15
|
+
const TYPED_TRANSPORT_PLATFORMS = ["VSCode", "Claude"];
|
|
16
|
+
/** Resolves the MCP configuration file written for a platform. */
|
|
17
|
+
const getMCPConfigPath = (projectRoot, platform) => {
|
|
18
|
+
if (platform === "Claude") return node_path.default.join(projectRoot, CLAUDE_CODE_MCP_CONFIG_FILENAME);
|
|
19
|
+
const relativeDir = node_path.default.dirname(require_installSkills_index.PLATFORMS_METADATA[platform]?.dir ?? ".");
|
|
20
|
+
return node_path.default.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);
|
|
21
|
+
};
|
|
22
|
+
/** Builds the Intlayer MCP server entry for a platform and transport. */
|
|
23
|
+
const getMCPServerConfig = (platform, transport) => {
|
|
24
|
+
const isTypedTransport = TYPED_TRANSPORT_PLATFORMS.includes(platform);
|
|
25
|
+
if (transport === "stdio") return {
|
|
26
|
+
command: "npx",
|
|
27
|
+
args: ["-y", "@intlayer/mcp"],
|
|
28
|
+
...isTypedTransport ? { type: "stdio" } : {}
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
url: "https://mcp.intlayer.org",
|
|
32
|
+
...isTypedTransport ? { type: "sse" } : { transport: "sse" }
|
|
33
|
+
};
|
|
34
|
+
};
|
|
13
35
|
/**
|
|
14
36
|
* Installs the Intlayer MCP server configuration for a specific platform.
|
|
37
|
+
* Every platform is configured at the project level (Claude Code included,
|
|
38
|
+
* through `.mcp.json`), so nothing outside the project is modified.
|
|
15
39
|
*/
|
|
16
40
|
const installMCP = async (projectRoot, platform, transport) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (platform === "Claude") configPath = CLAUDE_DESKTOP_CONFIG_PATH;
|
|
20
|
-
else {
|
|
21
|
-
const relativeDir = node_path.default.dirname(require_installSkills_index.PLATFORMS_METADATA[platform]?.dir ?? ".");
|
|
22
|
-
configPath = node_path.default.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);
|
|
23
|
-
if (platform === "VSCode") configKey = "servers";
|
|
24
|
-
}
|
|
41
|
+
const configPath = getMCPConfigPath(projectRoot, platform);
|
|
42
|
+
const serversKey = platform === "VSCode" ? "servers" : "mcpServers";
|
|
25
43
|
await node_fs.promises.mkdir(node_path.default.dirname(configPath), { recursive: true });
|
|
26
44
|
let config = {};
|
|
27
45
|
try {
|
|
28
46
|
const content = await node_fs.promises.readFile(configPath, "utf-8");
|
|
29
47
|
config = JSON.parse(content);
|
|
30
48
|
} catch {}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
37
|
-
if (platform === "VSCode") mcpConfig.type = "stdio";
|
|
38
|
-
config[configKey].intlayer = mcpConfig;
|
|
39
|
-
} else {
|
|
40
|
-
const mcpConfig = { url: "https://mcp.intlayer.org" };
|
|
41
|
-
if (platform === "VSCode") mcpConfig.type = "sse";
|
|
42
|
-
else mcpConfig.transport = "sse";
|
|
43
|
-
config[configKey].intlayer = mcpConfig;
|
|
44
|
-
}
|
|
49
|
+
const servers = config[serversKey] ?? {};
|
|
50
|
+
config[serversKey] = {
|
|
51
|
+
...servers,
|
|
52
|
+
intlayer: getMCPServerConfig(platform, transport)
|
|
53
|
+
};
|
|
45
54
|
await node_fs.promises.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
46
55
|
return `MCP server configuration updated in ${configPath}`;
|
|
47
56
|
};
|
|
48
57
|
|
|
49
58
|
//#endregion
|
|
59
|
+
exports.MCP_TRANSPORTS = MCP_TRANSPORTS;
|
|
50
60
|
exports.installMCP = installMCP;
|
|
51
61
|
//# sourceMappingURL=installMCP.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installMCP.cjs","names":["path","
|
|
1
|
+
{"version":3,"file":"installMCP.cjs","names":["path","PLATFORMS_METADATA","fs"],"sources":["../../../src/installMCP/installMCP.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { PLATFORMS_METADATA, type Platform } from '../installSkills';\n\nexport type MCPTransport = 'stdio' | 'sse';\n\n/** Transports accepted by `intlayer init mcp --transport`. */\nexport const MCP_TRANSPORTS: MCPTransport[] = ['stdio', 'sse'];\n\nconst MCP_CONFIG_FILENAME = 'mcp.json';\n\n/** Project-scoped MCP configuration file read by Claude Code. */\nconst CLAUDE_CODE_MCP_CONFIG_FILENAME = '.mcp.json';\n\n/** One MCP server entry, as written under the platform's servers key. */\ntype MCPServerConfig = {\n command?: string;\n args?: string[];\n url?: string;\n type?: MCPTransport;\n transport?: MCPTransport;\n};\n\n/** Parsed MCP configuration file, keeping any unrelated keys untouched. */\ntype MCPConfigFile = Record<string, unknown>;\n\n/** Platforms whose MCP entries declare their transport as `type`. */\nconst TYPED_TRANSPORT_PLATFORMS: Platform[] = ['VSCode', 'Claude'];\n\n/** Resolves the MCP configuration file written for a platform. */\nconst getMCPConfigPath = (projectRoot: string, platform: Platform): string => {\n if (platform === 'Claude') {\n return path.join(projectRoot, CLAUDE_CODE_MCP_CONFIG_FILENAME);\n }\n\n // e.g. `.cursor/skills` → `.cursor/mcp.json`\n const relativeDir = path.dirname(PLATFORMS_METADATA[platform]?.dir ?? '.');\n\n return path.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);\n};\n\n/** Builds the Intlayer MCP server entry for a platform and transport. */\nconst getMCPServerConfig = (\n platform: Platform,\n transport: MCPTransport\n): MCPServerConfig => {\n const isTypedTransport = TYPED_TRANSPORT_PLATFORMS.includes(platform);\n\n if (transport === 'stdio') {\n return {\n command: 'npx',\n args: ['-y', '@intlayer/mcp'],\n ...(isTypedTransport ? { type: 'stdio' } : {}),\n };\n }\n\n return {\n url: 'https://mcp.intlayer.org',\n ...(isTypedTransport ? { type: 'sse' } : { transport: 'sse' }),\n };\n};\n\n/**\n * Installs the Intlayer MCP server configuration for a specific platform.\n * Every platform is configured at the project level (Claude Code included,\n * through `.mcp.json`), so nothing outside the project is modified.\n */\nexport const installMCP = async (\n projectRoot: string,\n platform: Platform,\n transport: MCPTransport\n): Promise<string> => {\n const configPath = getMCPConfigPath(projectRoot, platform);\n const serversKey = platform === 'VSCode' ? 'servers' : 'mcpServers';\n\n // Ensure the configuration directory exists\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n\n let config: MCPConfigFile = {};\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n config = JSON.parse(content) as MCPConfigFile;\n } catch {\n // File doesn't exist or is invalid JSON, start fresh\n }\n\n const servers = (config[serversKey] ?? {}) as Record<string, MCPServerConfig>;\n\n config[serversKey] = {\n ...servers,\n intlayer: getMCPServerConfig(platform, transport),\n };\n\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n\n return `MCP server configuration updated in ${configPath}`;\n};\n"],"mappings":";;;;;;;;;AAOA,MAAa,iBAAiC,CAAC,SAAS,KAAK;AAE7D,MAAM,sBAAsB;;AAG5B,MAAM,kCAAkC;;AAexC,MAAM,4BAAwC,CAAC,UAAU,QAAQ;;AAGjE,MAAM,oBAAoB,aAAqB,aAA+B;CAC5E,IAAI,aAAa,UACf,OAAOA,kBAAK,KAAK,aAAa,+BAA+B;CAI/D,MAAM,cAAcA,kBAAK,QAAQC,+CAAmB,SAAS,EAAE,OAAO,GAAG;CAEzE,OAAOD,kBAAK,KAAK,aAAa,aAAa,mBAAmB;AAChE;;AAGA,MAAM,sBACJ,UACA,cACoB;CACpB,MAAM,mBAAmB,0BAA0B,SAAS,QAAQ;CAEpE,IAAI,cAAc,SAChB,OAAO;EACL,SAAS;EACT,MAAM,CAAC,MAAM,eAAe;EAC5B,GAAI,mBAAmB,EAAE,MAAM,QAAQ,IAAI,CAAC;CAC9C;CAGF,OAAO;EACL,KAAK;EACL,GAAI,mBAAmB,EAAE,MAAM,MAAM,IAAI,EAAE,WAAW,MAAM;CAC9D;AACF;;;;;;AAOA,MAAa,aAAa,OACxB,aACA,UACA,cACoB;CACpB,MAAM,aAAa,iBAAiB,aAAa,QAAQ;CACzD,MAAM,aAAa,aAAa,WAAW,YAAY;CAGvD,MAAME,iBAAG,MAAMF,kBAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAE5D,IAAI,SAAwB,CAAC;CAC7B,IAAI;EACF,MAAM,UAAU,MAAME,iBAAG,SAAS,YAAY,OAAO;EACrD,SAAS,KAAK,MAAM,OAAO;CAC7B,QAAQ,CAER;CAEA,MAAM,UAAW,OAAO,eAAe,CAAC;CAExC,OAAO,cAAc;EACnB,GAAG;EACH,UAAU,mBAAmB,UAAU,SAAS;CAClD;CAEA,MAAMA,iBAAG,UAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;CAEvE,OAAO,uCAAuC;AAChD"}
|
|
@@ -175,7 +175,7 @@ const PLATFORMS_METADATA = {
|
|
|
175
175
|
Claude: {
|
|
176
176
|
label: "Claude Code",
|
|
177
177
|
dir: ".claude/skills",
|
|
178
|
-
check: () => process.env.CLAUDE === "true"
|
|
178
|
+
check: () => process.env.CLAUDE === "true" || process.env.CLAUDECODE === "1"
|
|
179
179
|
},
|
|
180
180
|
GitHub: {
|
|
181
181
|
label: "GitHub Copilot Workspace",
|
|
@@ -293,6 +293,30 @@ const PLATFORMS_METADATA = {
|
|
|
293
293
|
};
|
|
294
294
|
const PLATFORMS = Object.keys(PLATFORMS_METADATA);
|
|
295
295
|
/**
|
|
296
|
+
* Root folders too common to identify a platform on their own (e.g. `.github`
|
|
297
|
+
* exists in most repositories regardless of the AI tool in use).
|
|
298
|
+
*/
|
|
299
|
+
const AMBIGUOUS_PLATFORM_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
300
|
+
".github",
|
|
301
|
+
".vscode",
|
|
302
|
+
"skills"
|
|
303
|
+
]);
|
|
304
|
+
/** Root config folder of a platform (e.g. `.cursor`), if it identifies it. */
|
|
305
|
+
const getPlatformDirectory = (platform) => {
|
|
306
|
+
const [rootDirectory] = (PLATFORMS_METADATA[platform]?.dir ?? "").split("/");
|
|
307
|
+
if (!rootDirectory || AMBIGUOUS_PLATFORM_DIRECTORIES.has(rootDirectory)) return;
|
|
308
|
+
return rootDirectory;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Detects the AI platform in use. The environment of the running tool wins;
|
|
312
|
+
* otherwise the first platform whose config folder (`.claude`, `.cursor`…)
|
|
313
|
+
* exists in the project root is returned.
|
|
314
|
+
*/
|
|
315
|
+
const detectPlatform = (projectRoot) => PLATFORMS.find((platform) => PLATFORMS_METADATA[platform]?.check?.()) ?? PLATFORMS.find((platform) => {
|
|
316
|
+
const platformDirectory = getPlatformDirectory(platform);
|
|
317
|
+
return platformDirectory !== void 0 && (0, node_fs.existsSync)(node_path.default.join(projectRoot, platformDirectory));
|
|
318
|
+
});
|
|
319
|
+
/**
|
|
296
320
|
* Maps specific skill keys to special filenames if they differ from standard snake_case.
|
|
297
321
|
*/
|
|
298
322
|
const SKILL_FILENAME_MAP = {};
|
|
@@ -426,6 +450,7 @@ exports.PLATFORMS = PLATFORMS;
|
|
|
426
450
|
exports.PLATFORMS_METADATA = PLATFORMS_METADATA;
|
|
427
451
|
exports.SKILLS = SKILLS;
|
|
428
452
|
exports.SKILLS_METADATA = SKILLS_METADATA;
|
|
453
|
+
exports.detectPlatform = detectPlatform;
|
|
429
454
|
exports.getInitialSkills = getInitialSkills;
|
|
430
455
|
exports.installSkills = installSkills;
|
|
431
456
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["readAsset","path","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n BundleOptimization:\n 'Purge, minify and import modes; writing code the bundle optimizer can follow',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'BundleOptimization',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":";;;;;;;;;;;;;AASA,MAAa,kBAAkB;CAC7B,QAAQ;CACR,SAAS;CACT,UACE;CACF,OAAO;CACP,KAAK;CACL,UACE;CACF,oBACE;CACF,eAAe;CACf,UAAU;CACV,QACE;CACF,QAAQ;CACR,OAAO;CACP,KAAK;CACL,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,OAAO;CACP,OAAO;CACP,KAAK;CACL,SAAS;CACT,OAAO;CACP,SACE;AACJ;AAIA,MAAa,SAAS,OAAO,KAAK,eAAe;;AAGjD,MAAM,cAAuB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;AAOA,MAAM,yBAA2D;CAC/D,QAAQ,CAAC,QAAQ,eAAe;CAChC,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;CACA,QAAQ,CAAC,UAAU,iBAAiB;CACpC,OAAO;EAAC;EAAY;EAAkB;CAAgB;CACtD,KAAK;EAAC;EAAO;EAAQ;EAAgB;CAAe;CACpD,QAAQ;EAAC;EAAU;EAAiB;CAAiB;CACrD,SAAS;EAAC;EAAiB;EAAsB;CAAkB;CACnE,OAAO,CAAC,SAAS,gBAAgB;CACjC,KAAK,CAAC,OAAO,cAAc;CAC3B,SAAS,CAAC,kBAAkB;CAC5B,OAAO,CAAC,SAAS,gBAAgB;CACjC,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBACX,iBACY;CACZ,MAAM,iBAAiB,OAAO,QAAQ,UACpC,uBAAuB,MAAM,EAAE,MAC5B,gBAAgB,eAAe,YAClC,CACF;CAEA,OAAO,CAAC,GAAG,aAAa,GAAG,cAAc;AAC3C;;;;AAWA,MAAa,qBAAuD;CAClE,QAAQ;EACN,OAAO;EACP,KAAK;EACL,aACE,QAAQ,IAAI,WAAW,UAAU,QAAQ,IAAI,iBAAiB;CAClE;CACA,UAAU;EACR,OAAO;EACP,KAAK;EACL,aACE,QAAQ,IAAI,aAAa,UACzB,QAAQ,IAAI,iBAAiB;CACjC;CACA,MAAM;EACJ,OAAO;EACP,KAAK;EACL,aACE,QAAQ,IAAI,SAAS,UAAU,QAAQ,IAAI,iBAAiB;CAChE;CACA,QAAQ;EACN,OAAO;EACP,KAAK;EACL,aAAa,QAAQ,IAAI,YAAY;CACvC;CACA,QAAQ;EACN,OAAO;EACP,KAAK;EACL,aACE,QAAQ,IAAI,WAAW,UAAU,QAAQ,IAAI,iBAAiB;CAClE;CACA,UAAU;EACR,OAAO;EACP,KAAK;EACL,aAAa,QAAQ,IAAI,aAAa;CACxC;CACA,QAAQ;EACN,OAAO;EACP,KAAK;EACL,aAAa,QAAQ,IAAI,WAAW;CACtC;CACA,QAAQ;EACN,OAAO;EACP,KAAK;EACL,aACE,QAAQ,IAAI,mBAAmB,UAAU,CAAC,CAAC,QAAQ,IAAI;CAC3D;CACA,aAAa;EACX,OAAO;EACP,KAAK;CACP;CACA,SAAS;EACP,OAAO;EACP,KAAK;CACP;CACA,UAAU;EACR,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,WAAW;EACT,OAAO;EACP,KAAK;CACP;CACA,aAAa;EACX,OAAO;EACP,KAAK;CACP;CACA,UAAU;EACR,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,UAAU;EACR,OAAO;EACP,KAAK;CACP;CACA,MAAM;EACJ,OAAO;EACP,KAAK;CACP;CACA,MAAM;EACJ,OAAO;EACP,KAAK;CACP;CACA,QAAQ;EACN,OAAO;EACP,KAAK;CACP;CACA,aAAa;EACX,OAAO;EACP,KAAK;CACP;CACA,KAAK;EACH,OAAO;EACP,KAAK;CACP;CACA,WAAW;EACT,OAAO;EACP,KAAK;CACP;CACA,IAAI;EACF,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,MAAM;EACJ,OAAO;EACP,KAAK;CACP;CACA,SAAS;EACP,OAAO;EACP,KAAK;CACP;CACA,UAAU;EACR,OAAO;EACP,KAAK;CACP;CACA,SAAS;EACP,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;CACA,OAAO;EACL,OAAO;EACP,KAAK;CACP;AACF;AAIA,MAAa,YAAY,OAAO,KAAK,kBAAkB;;;;AAKvD,MAAM,qBAAqD,CAAC;;;;AAK5D,MAAM,oBAAoB,QACxB,IAAI,QAAQ,sBAAsB,OAAO,CAAC,CAAC,YAAY;;;;AAKzD,MAAM,mBAAmB,UAAyB;CAEhD,MAAM,WAAW,YADA,mBAAmB,UAAU,iBAAiB,KAAK,EAC9B;CAEtC,IAAI;EACF,OAAOA,+BAAU,QAAQ;CAC3B,QAAQ;EACN,QAAQ,KACN,4CAA4C,MAAM,MAAM,UAC1D;EACA,OAAO;CACT;AACF;;;;AAKA,MAAM,0BAAkC;CACtC,IAAI;EACF,OAAOA,+BAAU,cAAc;CACjC,QAAQ;EACN,QAAQ,KAAK,0CAA0C;EACvD,OAAO;CACT;AACF;AAEA,MAAM,sCAAsB,IAAI,IAAI,CAAC,cAAc,CAAC;;AAGpD,MAAM,sBAAsB;;;;;;;;AAS5B,MAAM,mBAAmB,QAA2B;CAClD,MAAM,SAAS,IAAI,IAAI,GAAG;CAE1B,IACE,OAAO,aAAa,YACpB,CAAC,oBAAoB,IAAI,OAAO,QAAQ,GAExC,MAAM,IAAI,MAAM,qCAAqC,OAAO,UAAU;CAGxE,OAAO;AACT;;;;;;;;;;;;;AAcA,MAAM,kBAAkB,OAAO,QAAiC;CAC9D,IAAI,SAAS,gBAAgB,GAAG;CAEhC,KAAK,IAAI,MAAM,GAAG,OAAO,qBAAqB,OAAO;EACnD,MAAM,WAAW,MAAM,MAAM,QAAQ,EAAE,UAAU,SAAS,CAAC;EAE3D,IAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;GACnD,MAAM,WAAW,SAAS,QAAQ,IAAI,UAAU;GAEhD,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,mBAAmB,IAAI,8BAA8B;GAGvE,SAAS,gBAAgB,IAAI,IAAI,UAAU,MAAM,CAAC;GAClD;EACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,mBAAmB,IAAI,IAAI,SAAS,YAAY;EAGlE,OAAO,SAAS,KAAK;CACvB;CAEA,MAAM,IAAI,MAAM,mBAAmB,IAAI,qBAAqB;AAC9D;;;;;AAMA,MAAa,gBAAgB,OAC3B,aACA,UACA,WACoB;CAEpB,MAAM,cAAc,mBAAmB,SAAS,EAAE,OAAO;CACzD,MAAM,gBAAgBC,kBAAK,KAAK,aAAa,WAAW;CAGxD,MAAMC,iBAAG,MAAM,eAAe,EAAE,WAAW,KAAK,CAAC;CAEjD,MAAM,gBAA0B,CAAC;CACjC,MAAM,iBAAiB,kBAAkB;CAEzC,KAAK,MAAM,SAAS,QAAQ;EAE1B,MAAM,YAAY,YADD,mBAAmB,UAAU,iBAAiB,KAAK;EAEpE,MAAM,eAAe,gBAAgB,KAAK;EAE1C,IAAI,CAAC,cAAc;EAGnB,MAAM,OAAO,MAAM,KACjB,IAAI,IAAI,aAAa,MAAM,uCAAuC,KAAK,CAAC,CAAC,CAC3E;EAGA,MAAM,WAAWD,kBAAK,KAAK,eAAe,SAAS;EACnD,MAAM,eAAeA,kBAAK,KAAK,UAAU,YAAY;EAGrD,MAAMC,iBAAG,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;EAGhD,IAAI,gBACF,MAAMA,iBAAG,UACPD,kBAAK,KAAK,UAAU,YAAY,GAChC,gBACA,OACF;EAGF,IAAI,sBAAsB;EAG1B,MAAM,mBAAmB,KAAK,IAAI,OAAO,QAAQ;GAC/C,IAAI;IACF,MAAM,UAAU,MAAM,gBAAgB,GAAG;IACzC,MAAM,eAAWE,6CAA0C,OAAO;IAElE,IAAI,WAAW;IAGf,IAAI,MAAM,QAAQ,SAAS,KAAK,GAC9B,WAAW,SAAS,MACjB,QAAQ,SAAS,SAAS,KAAK,CAAC,CAChC,KAAK,GAAG,CAAC,CAET,WAAW,KAAK,GAAG;SAGtB,WADgB,IAAI,IAAI,GAAG,CAAC,CAAC,SAE1B,MAAM,GAAG,CAAC,CACV,QAAQ,SAAS,QAAQ,SAAS,KAAK,CAAC,CACxC,KAAK,SAAS,KAAK,QAAQ,OAAO,EAAE,CAAC,CAAC,CACtC,KAAK,GAAG;IAIb,WAAW,WAAW,GAAG,SAAS,OAAO;IAGzC,OAAO;KACL;KACA,4BAJiC;KAKjC;KACA;KACA,SAAS;IACX;GACF,SAAS,OAAO;IACd,QAAQ,KACN,mCAAmC,IAAI,aAAa,SACpD,KACF;IACA,OAAO;KAAE;KAAK,SAAS;IAAM;GAC/B;EACF,CAAC;EAED,MAAM,UAAU,MAAM,QAAQ,IAAI,gBAAgB;EAGlD,KAAK,MAAM,OAAO,SAChB,IAAI,IAAI,WAAW,IAAI,YAAY,IAAI,WAAW,IAAI,cAAc;GAElE,MAAMD,iBAAG,UACPD,kBAAK,KAAK,cAAc,IAAI,QAAQ,GACpC,IAAI,SACJ,OACF;GAGA,sBAAsB,oBAAoB,WACxC,IAAI,KACJ,IAAI,YACN;EACF;EAIF,MAAM,WAAWA,kBAAK,KAAK,UAAU,UAAU;EAC/C,MAAMC,iBAAG,UAAU,UAAU,qBAAqB,OAAO;EACzD,cAAc,KAAK,GAAG,UAAU,UAAU;CAC5C;CAEA,IAAI,cAAc,WAAW,GAC3B,OAAO;CAGT,OAAO,GAAGE,0BAAE,WAAW,cAAc,OAAO,aAAa;AAC3D"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["existsSync","path","readAsset","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { existsSync, promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n BundleOptimization:\n 'Purge, minify and import modes; writing code the bundle optimizer can follow',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'BundleOptimization',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () =>\n process.env.CLAUDE === 'true' || process.env.CLAUDECODE === '1',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Root folders too common to identify a platform on their own (e.g. `.github`\n * exists in most repositories regardless of the AI tool in use).\n */\nconst AMBIGUOUS_PLATFORM_DIRECTORIES = new Set([\n '.github',\n '.vscode',\n 'skills',\n]);\n\n/** Root config folder of a platform (e.g. `.cursor`), if it identifies it. */\nconst getPlatformDirectory = (platform: Platform): string | undefined => {\n const [rootDirectory] = (PLATFORMS_METADATA[platform]?.dir ?? '').split('/');\n\n if (!rootDirectory || AMBIGUOUS_PLATFORM_DIRECTORIES.has(rootDirectory)) {\n return undefined;\n }\n\n return rootDirectory;\n};\n\n/**\n * Detects the AI platform in use. The environment of the running tool wins;\n * otherwise the first platform whose config folder (`.claude`, `.cursor`…)\n * exists in the project root is returned.\n */\nexport const detectPlatform = (projectRoot: string): Platform | undefined =>\n PLATFORMS.find((platform) => PLATFORMS_METADATA[platform]?.check?.()) ??\n PLATFORMS.find((platform) => {\n const platformDirectory = getPlatformDirectory(platform);\n\n return (\n platformDirectory !== undefined &&\n existsSync(path.join(projectRoot, platformDirectory))\n );\n });\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
2
|
let node_path = require("node:path");
|
|
4
3
|
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
5
4
|
let node_fs = require("node:fs");
|
|
6
5
|
let _intlayer_config_built = require("@intlayer/config/built");
|
|
7
6
|
let simple_git = require("simple-git");
|
|
8
|
-
simple_git = require_runtime.__toESM(simple_git);
|
|
9
7
|
|
|
10
8
|
//#region src/listGitFiles.ts
|
|
11
9
|
const getGitRootDir = async () => {
|
|
12
10
|
try {
|
|
13
|
-
return (await (0, simple_git.
|
|
11
|
+
return (await (0, simple_git.simpleGit)().revparse(["--show-toplevel"])).trim();
|
|
14
12
|
} catch (error) {
|
|
15
13
|
(0, _intlayer_config_logger.getAppLogger)({ log: _intlayer_config_built.log })(`Error getting git root directory: ${error}`, { level: "error" });
|
|
16
14
|
return null;
|
|
@@ -18,7 +16,7 @@ const getGitRootDir = async () => {
|
|
|
18
16
|
};
|
|
19
17
|
const listGitFiles = async ({ mode, baseRef = "origin/main", currentRef = "HEAD", absolute = true }) => {
|
|
20
18
|
try {
|
|
21
|
-
const git = (0, simple_git.
|
|
19
|
+
const git = (0, simple_git.simpleGit)();
|
|
22
20
|
const diff = /* @__PURE__ */ new Set();
|
|
23
21
|
if (mode.includes("untracked")) (await git.status()).not_added.forEach((file) => {
|
|
24
22
|
diff.add(file);
|
|
@@ -46,7 +44,7 @@ const listGitFiles = async ({ mode, baseRef = "origin/main", currentRef = "HEAD"
|
|
|
46
44
|
}
|
|
47
45
|
};
|
|
48
46
|
const listGitLines = async (filePath, { mode, baseRef = "origin/main", currentRef = "HEAD" }) => {
|
|
49
|
-
const git = (0, simple_git.
|
|
47
|
+
const git = (0, simple_git.simpleGit)();
|
|
50
48
|
const changedLines = /* @__PURE__ */ new Set();
|
|
51
49
|
/**
|
|
52
50
|
* Extracts line numbers from a diff generated with `--unified=0`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listGitFiles.cjs","names":["simpleGit","getAppLogger","join","readFileSync"],"sources":["../../src/listGitFiles.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from '@intlayer/config/built';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport simpleGit from 'simple-git';\n\nexport type DiffMode = 'gitDiff' | 'uncommitted' | 'unpushed' | 'untracked';\n\nconst getGitRootDir = async (): Promise<string | null> => {\n try {\n const git = simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (error) {\n const appLogger = getAppLogger({ log });\n appLogger(`Error getting git root directory: ${error}`, {\n level: 'error',\n });\n return null;\n }\n};\n\nexport type ListGitFilesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n absolute?: boolean;\n};\n\nexport const listGitFiles = async ({\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n absolute = true,\n}: ListGitFilesOptions) => {\n try {\n const git = simpleGit();\n const diff: Set<string> = new Set();\n\n if (mode.includes('untracked')) {\n const status = await git.status();\n status.not_added.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('uncommitted')) {\n // Get uncommitted changes\n const uncommittedDiff = await git.diff(['--name-only', 'HEAD']);\n\n const uncommittedFiles = uncommittedDiff.split('\\n').filter(Boolean);\n\n uncommittedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('unpushed')) {\n // Get unpushed commits\n const unpushedDiff = await git.diff(['--name-only', '@{push}...HEAD']);\n\n const unpushedFiles = unpushedDiff.split('\\n').filter(Boolean);\n\n unpushedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('gitDiff')) {\n // Get the base branch (usually main/master) from CI environment\n\n await git.fetch(baseRef);\n\n const diffBranch = await git.diff([\n '--name-only',\n `${baseRef}...${currentRef}`,\n ]);\n\n const gitDiffFiles = diffBranch.split('\\n').filter(Boolean);\n\n gitDiffFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (absolute) {\n const gitRootDir = await getGitRootDir();\n if (!gitRootDir) {\n return [];\n }\n return Array.from(diff).map((file) => join(gitRootDir, file));\n }\n\n return Array.from(diff);\n } catch (error) {\n console.warn('Failed to get changes list:', error);\n }\n};\n\nexport type ListGitLinesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n};\n\nexport const listGitLines = async (\n filePath: string,\n {\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n }: ListGitLinesOptions\n): Promise<number[]> => {\n const git = simpleGit();\n // We collect **line numbers** (1-based) that were modified/added by the diff.\n // Using a Set ensures uniqueness when the same line is reported by several modes.\n const changedLines: Set<number> = new Set();\n\n /**\n * Extracts line numbers from a diff generated with `--unified=0`.\n * Each hunk header looks like: @@ -<oldStart>,<oldCount> +<newStart>,<newCount> @@\n * We consider both the \"+\" (new) side for additions and the \"-\" (old) side for deletions.\n * For deletions, we add the line before and after the deletion point in the current file.\n */\n const collectLinesFromDiff = (diffOutput: string) => {\n const hunkRegex = /@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/g;\n let match: RegExpExecArray | null;\n\n // biome-ignore lint/suspicious/noAssignInExpressions: Used in while loop condition\n while ((match = hunkRegex.exec(diffOutput)) !== null) {\n const oldCount = match[2] ? Number(match[2]) : 1;\n const newStart = Number(match[3]);\n const newCount = match[4] ? Number(match[4]) : 1;\n\n // Handle additions/modifications (+ side)\n if (newCount > 0) {\n for (let i = 0; i < newCount; i++) {\n changedLines.add(newStart + i);\n }\n }\n\n // Handle deletions (- side)\n if (oldCount > 0 && newCount === 0) {\n // For deletions, add the line before and after the deletion point\n // The deletion point in the new file is at newStart\n if (newStart > 1) {\n changedLines.add(newStart - 1); // Line before deletion\n }\n changedLines.add(newStart); // Line after deletion (if it exists)\n }\n }\n };\n\n // 1. Handle untracked files – when a file is untracked its entire content is new.\n if (mode.includes('untracked')) {\n const status = await git.status();\n const isUntracked = status.not_added.includes(filePath);\n if (isUntracked) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n content.split('\\n').forEach((_, idx) => {\n changedLines.add(idx + 1);\n });\n } catch {\n // ignore read errors – file may have been deleted, etc.\n }\n }\n }\n\n // 2. Uncommitted changes (working tree vs HEAD)\n if (mode.includes('uncommitted')) {\n const diffOutput = await git.diff(['--unified=0', 'HEAD', '--', filePath]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 3. Unpushed commits – compare local branch to its upstream\n if (mode.includes('unpushed')) {\n const diffOutput = await git.diff([\n '--unified=0',\n '@{push}...HEAD',\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 4. Regular git diff between baseRef and currentRef (e.g., CI pull-request diff)\n if (mode.includes('gitDiff')) {\n await git.fetch(baseRef);\n const diffOutput = await git.diff([\n '--unified=0',\n `${baseRef}...${currentRef}`,\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // Return the list sorted for convenience\n return Array.from(changedLines).sort((a, b) => a - b);\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"listGitFiles.cjs","names":["simpleGit","getAppLogger","join","readFileSync"],"sources":["../../src/listGitFiles.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from '@intlayer/config/built';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport { simpleGit } from 'simple-git';\n\nexport type DiffMode = 'gitDiff' | 'uncommitted' | 'unpushed' | 'untracked';\n\nconst getGitRootDir = async (): Promise<string | null> => {\n try {\n const git = simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (error) {\n const appLogger = getAppLogger({ log });\n appLogger(`Error getting git root directory: ${error}`, {\n level: 'error',\n });\n return null;\n }\n};\n\nexport type ListGitFilesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n absolute?: boolean;\n};\n\nexport const listGitFiles = async ({\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n absolute = true,\n}: ListGitFilesOptions) => {\n try {\n const git = simpleGit();\n const diff: Set<string> = new Set();\n\n if (mode.includes('untracked')) {\n const status = await git.status();\n status.not_added.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('uncommitted')) {\n // Get uncommitted changes\n const uncommittedDiff = await git.diff(['--name-only', 'HEAD']);\n\n const uncommittedFiles = uncommittedDiff.split('\\n').filter(Boolean);\n\n uncommittedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('unpushed')) {\n // Get unpushed commits\n const unpushedDiff = await git.diff(['--name-only', '@{push}...HEAD']);\n\n const unpushedFiles = unpushedDiff.split('\\n').filter(Boolean);\n\n unpushedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('gitDiff')) {\n // Get the base branch (usually main/master) from CI environment\n\n await git.fetch(baseRef);\n\n const diffBranch = await git.diff([\n '--name-only',\n `${baseRef}...${currentRef}`,\n ]);\n\n const gitDiffFiles = diffBranch.split('\\n').filter(Boolean);\n\n gitDiffFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (absolute) {\n const gitRootDir = await getGitRootDir();\n if (!gitRootDir) {\n return [];\n }\n return Array.from(diff).map((file) => join(gitRootDir, file));\n }\n\n return Array.from(diff);\n } catch (error) {\n console.warn('Failed to get changes list:', error);\n }\n};\n\nexport type ListGitLinesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n};\n\nexport const listGitLines = async (\n filePath: string,\n {\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n }: ListGitLinesOptions\n): Promise<number[]> => {\n const git = simpleGit();\n // We collect **line numbers** (1-based) that were modified/added by the diff.\n // Using a Set ensures uniqueness when the same line is reported by several modes.\n const changedLines: Set<number> = new Set();\n\n /**\n * Extracts line numbers from a diff generated with `--unified=0`.\n * Each hunk header looks like: @@ -<oldStart>,<oldCount> +<newStart>,<newCount> @@\n * We consider both the \"+\" (new) side for additions and the \"-\" (old) side for deletions.\n * For deletions, we add the line before and after the deletion point in the current file.\n */\n const collectLinesFromDiff = (diffOutput: string) => {\n const hunkRegex = /@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/g;\n let match: RegExpExecArray | null;\n\n // biome-ignore lint/suspicious/noAssignInExpressions: Used in while loop condition\n while ((match = hunkRegex.exec(diffOutput)) !== null) {\n const oldCount = match[2] ? Number(match[2]) : 1;\n const newStart = Number(match[3]);\n const newCount = match[4] ? Number(match[4]) : 1;\n\n // Handle additions/modifications (+ side)\n if (newCount > 0) {\n for (let i = 0; i < newCount; i++) {\n changedLines.add(newStart + i);\n }\n }\n\n // Handle deletions (- side)\n if (oldCount > 0 && newCount === 0) {\n // For deletions, add the line before and after the deletion point\n // The deletion point in the new file is at newStart\n if (newStart > 1) {\n changedLines.add(newStart - 1); // Line before deletion\n }\n changedLines.add(newStart); // Line after deletion (if it exists)\n }\n }\n };\n\n // 1. Handle untracked files – when a file is untracked its entire content is new.\n if (mode.includes('untracked')) {\n const status = await git.status();\n const isUntracked = status.not_added.includes(filePath);\n if (isUntracked) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n content.split('\\n').forEach((_, idx) => {\n changedLines.add(idx + 1);\n });\n } catch {\n // ignore read errors – file may have been deleted, etc.\n }\n }\n }\n\n // 2. Uncommitted changes (working tree vs HEAD)\n if (mode.includes('uncommitted')) {\n const diffOutput = await git.diff(['--unified=0', 'HEAD', '--', filePath]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 3. Unpushed commits – compare local branch to its upstream\n if (mode.includes('unpushed')) {\n const diffOutput = await git.diff([\n '--unified=0',\n '@{push}...HEAD',\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 4. Regular git diff between baseRef and currentRef (e.g., CI pull-request diff)\n if (mode.includes('gitDiff')) {\n await git.fetch(baseRef);\n const diffOutput = await git.diff([\n '--unified=0',\n `${baseRef}...${currentRef}`,\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // Return the list sorted for convenience\n return Array.from(changedLines).sort((a, b) => a - b);\n};\n"],"mappings":"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"}
|
|
@@ -5,7 +5,6 @@ let _intlayer_config_node = require("@intlayer/config/node");
|
|
|
5
5
|
let fast_glob = require("fast-glob");
|
|
6
6
|
fast_glob = require_runtime.__toESM(fast_glob);
|
|
7
7
|
let simple_git = require("simple-git");
|
|
8
|
-
simple_git = require_runtime.__toESM(simple_git);
|
|
9
8
|
|
|
10
9
|
//#region src/listProjects.ts
|
|
11
10
|
/**
|
|
@@ -14,7 +13,7 @@ simple_git = require_runtime.__toESM(simple_git);
|
|
|
14
13
|
*/
|
|
15
14
|
const getGitRootDir = async (cwd) => {
|
|
16
15
|
try {
|
|
17
|
-
return (await (cwd ? (0, simple_git.
|
|
16
|
+
return (await (cwd ? (0, simple_git.simpleGit)(cwd) : (0, simple_git.simpleGit)()).revparse(["--show-toplevel"])).trim();
|
|
18
17
|
} catch (_error) {
|
|
19
18
|
return null;
|
|
20
19
|
}
|