@intlayer/cli 9.5.12 → 9.7.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.
Files changed (131) hide show
  1. package/dist/cjs/IntlayerEventListener.cjs.map +1 -1
  2. package/dist/cjs/_virtual/_utils_asset.cjs +1 -1
  3. package/dist/cjs/auth/login.cjs +11 -0
  4. package/dist/cjs/auth/login.cjs.map +1 -1
  5. package/dist/cjs/auth/setupRepository.cjs +95 -0
  6. package/dist/cjs/auth/setupRepository.cjs.map +1 -0
  7. package/dist/cjs/ci.cjs +1 -1
  8. package/dist/cjs/cli.cjs +59 -14
  9. package/dist/cjs/cli.cjs.map +1 -1
  10. package/dist/cjs/editor.cjs +61 -32
  11. package/dist/cjs/editor.cjs.map +1 -1
  12. package/dist/cjs/extract.cjs +1 -1
  13. package/dist/cjs/fill/fill.cjs +25 -9
  14. package/dist/cjs/fill/fill.cjs.map +1 -1
  15. package/dist/cjs/fill/translateDictionary.cjs.map +1 -1
  16. package/dist/cjs/getTargetDictionary.cjs +1 -1
  17. package/dist/cjs/index.cjs +29 -1
  18. package/dist/cjs/init.cjs +261 -36
  19. package/dist/cjs/init.cjs.map +1 -1
  20. package/dist/cjs/initChromeExtension.cjs +26 -3
  21. package/dist/cjs/initChromeExtension.cjs.map +1 -1
  22. package/dist/cjs/initInfra.cjs +6 -0
  23. package/dist/cjs/initInfra.cjs.map +1 -1
  24. package/dist/cjs/initMCP.cjs +18 -7
  25. package/dist/cjs/initMCP.cjs.map +1 -1
  26. package/dist/cjs/initSkills.cjs +37 -34
  27. package/dist/cjs/initSkills.cjs.map +1 -1
  28. package/dist/cjs/listContentDeclaration.cjs +1 -1
  29. package/dist/cjs/listProjects.cjs +1 -1
  30. package/dist/cjs/liveSync.cjs.map +1 -1
  31. package/dist/cjs/pull.cjs +1 -1
  32. package/dist/cjs/push/push.cjs +1 -1
  33. package/dist/cjs/reviewDoc/reviewDoc.cjs +1 -1
  34. package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -1
  35. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +1 -1
  36. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
  37. package/dist/cjs/translateDoc/translateDoc.cjs +1 -1
  38. package/dist/cjs/upgrade.cjs +1 -1
  39. package/dist/cjs/utils/checkAccess.cjs.map +1 -1
  40. package/dist/cjs/utils/detectGitRepository.cjs +87 -0
  41. package/dist/cjs/utils/detectGitRepository.cjs.map +1 -0
  42. package/dist/cjs/utils/getParentPackageJSON.cjs +1 -1
  43. package/dist/cjs/utils/isInteractiveTerminal.cjs +12 -0
  44. package/dist/cjs/utils/isInteractiveTerminal.cjs.map +1 -0
  45. package/dist/cjs/utils/parseChoice.cjs +21 -0
  46. package/dist/cjs/utils/parseChoice.cjs.map +1 -0
  47. package/dist/esm/IntlayerEventListener.mjs.map +1 -1
  48. package/dist/esm/_virtual/_utils_asset.mjs +1 -1
  49. package/dist/esm/auth/login.mjs +11 -0
  50. package/dist/esm/auth/login.mjs.map +1 -1
  51. package/dist/esm/auth/setupRepository.mjs +90 -0
  52. package/dist/esm/auth/setupRepository.mjs.map +1 -0
  53. package/dist/esm/ci.mjs +1 -1
  54. package/dist/esm/cli.mjs +59 -14
  55. package/dist/esm/cli.mjs.map +1 -1
  56. package/dist/esm/editor.mjs +62 -34
  57. package/dist/esm/editor.mjs.map +1 -1
  58. package/dist/esm/extract.mjs +1 -1
  59. package/dist/esm/fill/fill.mjs +25 -9
  60. package/dist/esm/fill/fill.mjs.map +1 -1
  61. package/dist/esm/fill/translateDictionary.mjs.map +1 -1
  62. package/dist/esm/getTargetDictionary.mjs +1 -1
  63. package/dist/esm/index.mjs +10 -5
  64. package/dist/esm/init.mjs +253 -38
  65. package/dist/esm/init.mjs.map +1 -1
  66. package/dist/esm/initChromeExtension.mjs +24 -4
  67. package/dist/esm/initChromeExtension.mjs.map +1 -1
  68. package/dist/esm/initInfra.mjs +6 -0
  69. package/dist/esm/initInfra.mjs.map +1 -1
  70. package/dist/esm/initMCP.mjs +21 -11
  71. package/dist/esm/initMCP.mjs.map +1 -1
  72. package/dist/esm/initSkills.mjs +37 -36
  73. package/dist/esm/initSkills.mjs.map +1 -1
  74. package/dist/esm/listContentDeclaration.mjs +1 -1
  75. package/dist/esm/listProjects.mjs +1 -1
  76. package/dist/esm/liveSync.mjs.map +1 -1
  77. package/dist/esm/pull.mjs +1 -1
  78. package/dist/esm/push/push.mjs +1 -1
  79. package/dist/esm/reviewDoc/reviewDoc.mjs +1 -1
  80. package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -1
  81. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +1 -1
  82. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
  83. package/dist/esm/translateDoc/translateDoc.mjs +1 -1
  84. package/dist/esm/upgrade.mjs +1 -1
  85. package/dist/esm/utils/checkAccess.mjs.map +1 -1
  86. package/dist/esm/utils/detectGitRepository.mjs +85 -0
  87. package/dist/esm/utils/detectGitRepository.mjs.map +1 -0
  88. package/dist/esm/utils/getParentPackageJSON.mjs +1 -1
  89. package/dist/esm/utils/isInteractiveTerminal.mjs +11 -0
  90. package/dist/esm/utils/isInteractiveTerminal.mjs.map +1 -0
  91. package/dist/esm/utils/parseChoice.mjs +20 -0
  92. package/dist/esm/utils/parseChoice.mjs.map +1 -0
  93. package/dist/types/IntlayerEventListener.d.ts +1 -1
  94. package/dist/types/IntlayerEventListener.d.ts.map +1 -1
  95. package/dist/types/auth/login.d.ts +5 -0
  96. package/dist/types/auth/login.d.ts.map +1 -1
  97. package/dist/types/auth/setupRepository.d.ts +25 -0
  98. package/dist/types/auth/setupRepository.d.ts.map +1 -0
  99. package/dist/types/editor.d.ts +10 -0
  100. package/dist/types/editor.d.ts.map +1 -1
  101. package/dist/types/fill/fill.d.ts +23 -2
  102. package/dist/types/fill/fill.d.ts.map +1 -1
  103. package/dist/types/fill/index.d.ts +2 -2
  104. package/dist/types/fill/translateDictionary.d.ts +1 -2
  105. package/dist/types/fill/translateDictionary.d.ts.map +1 -1
  106. package/dist/types/index.d.ts +11 -6
  107. package/dist/types/init.d.ts +55 -2
  108. package/dist/types/init.d.ts.map +1 -1
  109. package/dist/types/initChromeExtension.d.ts +19 -1
  110. package/dist/types/initChromeExtension.d.ts.map +1 -1
  111. package/dist/types/initInfra.d.ts.map +1 -1
  112. package/dist/types/initMCP.d.ts +16 -2
  113. package/dist/types/initMCP.d.ts.map +1 -1
  114. package/dist/types/initSkills.d.ts +23 -6
  115. package/dist/types/initSkills.d.ts.map +1 -1
  116. package/dist/types/liveSync.d.ts.map +1 -1
  117. package/dist/types/reviewDoc/reviewDoc.d.ts +1 -1
  118. package/dist/types/reviewDoc/reviewDoc.d.ts.map +1 -1
  119. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts +1 -2
  120. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts.map +1 -1
  121. package/dist/types/translateDoc/types.d.ts +1 -1
  122. package/dist/types/utils/checkAccess.d.ts +2 -1
  123. package/dist/types/utils/checkAccess.d.ts.map +1 -1
  124. package/dist/types/utils/detectGitRepository.d.ts +34 -0
  125. package/dist/types/utils/detectGitRepository.d.ts.map +1 -0
  126. package/dist/types/utils/isInteractiveTerminal.d.ts +9 -0
  127. package/dist/types/utils/isInteractiveTerminal.d.ts.map +1 -0
  128. package/dist/types/utils/parseChoice.d.ts +13 -0
  129. package/dist/types/utils/parseChoice.d.ts.map +1 -0
  130. package/dist/types/utils/selectCmsEnvironment.d.ts +1 -1
  131. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"init.cjs","names":["resolve","existsSync","join","hasLintTooling","readFileSync","loadPrompts","detectCompatI18nLibraries","hasUrlRoutingFramework","initIntlayer","initSkills","initMCP","initInfra","initChromeExtension","login","setupCmsCredentials"],"sources":["../../src/init.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport {\n detectCompatI18nLibraries,\n hasLintTooling,\n hasUrlRoutingFramework,\n type InitOptions,\n initIntlayer,\n logInitSuccessMessage,\n type RoutingMode,\n setupCmsCredentials,\n} from '@intlayer/engine/cli';\nimport { login } from './auth/login';\nimport { initChromeExtension } from './initChromeExtension';\nimport { initInfra } from './initInfra';\nimport { initMCP } from './initMCP';\nimport { initSkills } from './initSkills';\nimport { loadPrompts } from './loadPrompts';\n\nexport const findProjectRoot = (startDir: string) => {\n let currentDir = startDir;\n\n while (currentDir !== resolve(currentDir, '..')) {\n if (existsSync(join(currentDir, 'package.json'))) {\n return currentDir;\n }\n currentDir = resolve(currentDir, '..');\n }\n\n // If no package.json is found, return the start directory.\n // The initIntlayer function will handle the missing package.json error.\n return startDir;\n};\n\n/** Individually selectable setup steps exposed by the interactive init flow. */\nexport type InitStep =\n | 'packages'\n | 'githubActions'\n | 'projectSetup'\n | 'vscodeExtension'\n | 'lsp'\n | 'eslint'\n | 'skills'\n | 'mcp'\n | 'infra'\n | 'cms'\n | 'chromeExtension';\n\n/** A checkbox entry of the interactive init flow. */\nexport type InitStepOption = {\n value: InitStep;\n label: string;\n hint: string;\n};\n\n/**\n * Steps shown but not pre-selected. The infrastructure installer touches the\n * machine (downloads an app, pulls Docker images) and browser extensions open external URLs\n * rather than modifying the project, so they must be an explicit choice.\n */\nexport const OPT_IN_INIT_STEPS: InitStep[] = ['infra', 'chromeExtension'];\n\n/** Grouped checkbox entries of the interactive init flow, in display order. */\nexport const INIT_STEP_GROUPS: Record<string, InitStepOption[]> = {\n Codebase: [\n {\n value: 'packages',\n label: 'Install & upgrade packages',\n hint: 'install missing Intlayer dependencies and upgrade outdated ones',\n },\n {\n value: 'projectSetup',\n label: 'Project setup',\n hint: 'intlayer config, tsconfig, bundler plugin, middleware/proxy and providers in layout/page',\n },\n {\n value: 'githubActions',\n label: 'CI/CD (GitHub Actions)',\n hint: 'scaffold the fill and test workflows that run on every pull request (covers every project in a monorepo)',\n },\n ],\n DevTools: [\n {\n value: 'vscodeExtension',\n label: 'VS Code extension',\n hint: 'recommend the Intlayer extension',\n },\n {\n value: 'eslint',\n label: 'Lint rules (ESLint / oxlint)',\n hint: 'flag hardcoded text and dynamic calls the compiler cannot optimize',\n },\n {\n value: 'chromeExtension',\n label: 'Chrome extension',\n hint: 'for audit, debug and analysis purpose',\n },\n ],\n 'Coding assistant': [\n {\n value: 'skills',\n label: 'AI skills',\n hint: 'install the Intlayer documentation as agent skills',\n },\n {\n value: 'mcp',\n label: 'MCP server',\n hint: 'configure the Intlayer MCP server',\n },\n {\n value: 'lsp',\n label: 'Editor LSP',\n hint: 'go-to-definition from keys to .content files',\n },\n ],\n CMS: [\n {\n value: 'cms',\n label: 'CMS',\n hint: 'log in through your browser, then store the credentials in your .env',\n },\n {\n value: 'infra',\n label: 'Infrastructure (desktop app / self-hosting)',\n hint: 'install the desktop app, or self-host with Docker (all-in-one or Compose)',\n },\n ],\n};\n\n/**\n * Locale routing choice: a `routing.mode` served through the locale proxy, or\n * `none` to leave routing to the app (`no-prefix` with the proxy disabled).\n */\nexport type LocaleRoutingChoice = RoutingMode | 'none';\n\n/** Locale routing strategies offered by the interactive init flow. */\nconst ROUTING_OPTIONS: Array<{\n value: LocaleRoutingChoice;\n label: string;\n hint: string;\n}> = [\n {\n value: 'prefix-no-default',\n label: 'Prefix all except the default locale',\n hint: '/about, /fr/about (default)',\n },\n {\n value: 'prefix-all',\n label: 'Prefix all locales',\n hint: '/en/about, /fr/about',\n },\n {\n value: 'no-prefix',\n label: 'No locale in the URL',\n hint: '/about',\n },\n {\n value: 'search-params',\n label: 'Use a search parameter',\n hint: '/about?locale=fr',\n },\n {\n value: 'none',\n label: 'No locale routing',\n hint: 'no proxy, no locale route segment — handle the locale yourself',\n },\n];\n\n/** Locale routing choices accepted by `--routing`. */\nexport const LOCALE_ROUTING_CHOICES = ROUTING_OPTIONS.map(\n (option) => option.value\n);\n\n/** Validates a `--routing` value, throwing on an unknown choice. */\nexport const parseLocaleRoutingChoice = (\n value: string\n): LocaleRoutingChoice => {\n const choice = LOCALE_ROUTING_CHOICES.find((routing) => routing === value);\n\n if (!choice) {\n throw new Error(\n `Invalid --routing value \"${value}\". Expected one of: ${LOCALE_ROUTING_CHOICES.join(', ')}.`\n );\n }\n\n return choice;\n};\n\n/** Maps a routing choice to the init options it sets. */\nexport const getRoutingInitOptions = (\n choice: LocaleRoutingChoice\n): Pick<InitOptions, 'routingMode' | 'enableProxy'> =>\n choice === 'none'\n ? { routingMode: 'no-prefix', enableProxy: false }\n : { routingMode: choice, enableProxy: true };\n\n/** Known ESLint and oxlint configuration file names. */\nexport const ESLINT_CONFIG_FILES = [\n 'eslint.config.js',\n 'eslint.config.mjs',\n 'eslint.config.cjs',\n 'eslint.config.ts',\n 'eslint.config.mts',\n 'eslint.config.cts',\n '.eslintrc.js',\n '.eslintrc.cjs',\n '.eslintrc.yaml',\n '.eslintrc.yml',\n '.eslintrc.json',\n '.eslintrc',\n '.oxlintrc.json',\n];\n\n/**\n * Checks whether ESLint or a compatible linter (oxlint) is installed or\n * configured in the project.\n */\nexport const isEslintInstalled = (\n dependencies: Record<string, string>,\n root?: string\n): boolean => {\n if (hasLintTooling(dependencies)) return true;\n if (dependencies.eslint || dependencies.oxlint) return true;\n\n if (root) {\n return ESLINT_CONFIG_FILES.some((file) => existsSync(join(root, file)));\n }\n\n return false;\n};\n\n/**\n * Computes the initial setup steps selected by default in the interactive prompt.\n * Steps like infrastructure and browser extension require opt-in, while\n * eslint is preselected only if installed on the project.\n */\nexport const getInitialInitSteps = (\n dependencies: Record<string, string>,\n root?: string\n): InitStep[] => {\n const isEslintPresent = isEslintInstalled(dependencies, root);\n\n return Object.values(INIT_STEP_GROUPS)\n .flat()\n .map((option) => option.value)\n .filter((step) => {\n if (OPT_IN_INIT_STEPS.includes(step)) return false;\n if (step === 'eslint' && !isEslintPresent) return false;\n return true;\n });\n};\n\n/** Reads the merged dependencies of the project at `root`. */\nexport const getProjectDependencies = (\n root: string\n): Record<string, string> => {\n try {\n const packageJsonPath = join(root, 'package.json');\n if (!existsSync(packageJsonPath)) return {};\n const { dependencies = {}, devDependencies = {} } = JSON.parse(\n readFileSync(packageJsonPath, 'utf-8')\n );\n return { ...dependencies, ...devDependencies };\n } catch {\n return {};\n }\n};\n\n/**\n * Runs `init` in interactive mode: prompts the user with a checkbox of setup\n * steps, then forwards the selection to {@link initIntlayer} (packages, GitHub\n * Actions, VS Code extension, LSP) and runs the dedicated skills/MCP installers\n * for the steps that own their own prompts. The `.gitignore` entry is not\n * offered as a checkbox — it is always added (unless `--no-gitignore` is set).\n */\nconst runInteractiveInit = async (\n root: string,\n baseOptions?: InitOptions\n): Promise<void> => {\n const p = await loadPrompts();\n\n p.intro('Initialize Intlayer');\n\n const projectDependencies = getProjectDependencies(root);\n\n const selected = await p.groupMultiselect<InitStep>({\n message: 'Select what you want to set up:',\n options: INIT_STEP_GROUPS,\n initialValues: getInitialInitSteps(projectDependencies, root),\n required: false,\n });\n\n if (p.isCancel(selected)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n const steps = selected as InitStep[];\n\n // Compat i18n library detection — never asked, always derived from the\n // installed packages. `detectMissingIntlayerPackages` reads the very same\n // dependency map to schedule the compat adapter, the sync plugin and the\n // catalog template, so a project without any of those packages is simply set\n // up on Intlayer alone.\n const detectedCompatLibraries =\n detectCompatI18nLibraries(projectDependencies);\n const hasCompatLib = detectedCompatLibraries.length > 0;\n\n if (hasCompatLib) {\n p.log.info(\n `Detected existing i18n ${detectedCompatLibraries.length > 1 ? 'libraries' : 'library'}: ${detectedCompatLibraries.join(', ')} — the matching Intlayer compat adapter and catalog sync will be set up.`\n );\n }\n\n // Locale routing → `routing.mode` + `routing.enableProxy` in the config, and\n // the route segment the framework scaffolding creates. Only asked for web\n // frontends; projects without URL routing (backend, React Native / Expo) keep\n // only `routing.storage` in a freshly created config. Skipped for compat\n // i18n libraries, which keep their own routing.\n let routingOptions: Pick<InitOptions, 'routingMode' | 'enableProxy'> = {};\n\n if (\n steps.includes('projectSetup') &&\n baseOptions?.routingMode === undefined &&\n !hasCompatLib &&\n hasUrlRoutingFramework(projectDependencies)\n ) {\n const selectedRouting = await p.select<LocaleRoutingChoice>({\n message: 'How should the locale appear in your URLs?',\n options: ROUTING_OPTIONS,\n initialValue: 'prefix-no-default',\n });\n\n if (p.isCancel(selectedRouting)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n routingOptions = getRoutingInitOptions(selectedRouting);\n }\n\n const options: InitOptions = {\n ...baseOptions,\n ...routingOptions,\n noInstallPackages: !steps.includes('packages'),\n // The `.gitignore` entry is tied to project setup.\n noGitignore: baseOptions?.noGitignore || !steps.includes('projectSetup'),\n // Respect explicit `--no-*` flags from the command line even when the\n // corresponding step is selected in the checkbox.\n noGithubActions:\n baseOptions?.noGithubActions || !steps.includes('githubActions'),\n noFrameworkSetup:\n baseOptions?.noFrameworkSetup || !steps.includes('projectSetup'),\n noVscodeExtension: !steps.includes('vscodeExtension'),\n noLsp: !steps.includes('lsp'),\n noEslint: !steps.includes('eslint'),\n skipFinalMessage: true,\n };\n\n const { guideUrl } = await initIntlayer(root, options);\n\n // Skills ask for the platform after the skill selection; MCP reuses it.\n const skillsPlatform = steps.includes('skills')\n ? await initSkills(root)\n : undefined;\n\n if (steps.includes('mcp')) {\n await initMCP(root, skillsPlatform);\n }\n\n // Delegated to the hosted install script, which owns its own menu.\n if (steps.includes('infra')) {\n await initInfra();\n }\n\n if (steps.includes('chromeExtension')) {\n await initChromeExtension();\n }\n\n // CMS / visual editor runs last: the browser login persists the access-key\n // credentials to `.env` and enables the editor in the config file. Kept last\n // so the browser flow does not interrupt setup.\n if (steps.includes('cms')) {\n p.log.info('Opening your browser to log in to the Intlayer CMS...');\n // `exitAfter: false` keeps the process alive so the flow can finish; the\n // credentials are persisted to `.env` and the editor enabled in the config.\n await login({\n exitAfter: false,\n onCredentials: (credentials) => setupCmsCredentials(root, credentials),\n });\n }\n\n p.outro('Intlayer initialization complete');\n\n if (guideUrl) {\n logInitSuccessMessage(guideUrl);\n }\n};\n\nexport const init = async (\n projectRoot?: string,\n options?: InitOptions,\n interactive?: boolean\n) => {\n const root = projectRoot\n ? findProjectRoot(resolve(projectRoot))\n : findProjectRoot(process.cwd());\n\n if (interactive) {\n await runInteractiveInit(root, options);\n return;\n }\n\n await initIntlayer(root, options);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"init.cjs","names":["resolve","existsSync","join","initIntlayer","loadPrompts","login","setupCmsCredentials","detectGitRepository","setupRepository","parseChoice","CONTENT_FORMATS_BY_LAYOUT","CATALOG_MESSAGE_FORMATS","hasLintTooling","readFileSync","detectCompatI18nLibraries","hasUrlRoutingFramework","initSkills","initMCP","initInfra","initChromeExtension","isInteractiveTerminal"],"sources":["../../src/init.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport {\n CATALOG_MESSAGE_FORMATS,\n type CatalogMessageFormat,\n CONTENT_FORMATS_BY_LAYOUT,\n type ContentFormat,\n type ContentLayout,\n detectCompatI18nLibraries,\n hasLintTooling,\n hasUrlRoutingFramework,\n type InitOptions,\n initIntlayer,\n logInitSuccessMessage,\n type RoutingMode,\n setupCmsCredentials,\n} from '@intlayer/engine/cli';\nimport { login } from './auth/login';\nimport { setupRepository } from './auth/setupRepository';\nimport { initChromeExtension } from './initChromeExtension';\nimport { initInfra } from './initInfra';\nimport { initMCP } from './initMCP';\nimport { initSkills } from './initSkills';\nimport { loadPrompts } from './loadPrompts';\nimport { detectGitRepository } from './utils/detectGitRepository';\nimport { isInteractiveTerminal } from './utils/isInteractiveTerminal';\nimport { parseChoice } from './utils/parseChoice';\n\nexport const findProjectRoot = (startDir: string) => {\n let currentDir = startDir;\n\n while (currentDir !== resolve(currentDir, '..')) {\n if (existsSync(join(currentDir, 'package.json'))) {\n return currentDir;\n }\n currentDir = resolve(currentDir, '..');\n }\n\n // If no package.json is found, return the start directory.\n // The initIntlayer function will handle the missing package.json error.\n return startDir;\n};\n\n/** Resolves the project root from `--project-root`, else the working directory. */\nexport const resolveProjectRoot = (projectRoot?: string): string =>\n findProjectRoot(projectRoot ? resolve(projectRoot) : process.cwd());\n\n/** Individually selectable setup steps exposed by the interactive init flow. */\nexport type InitStep =\n | 'packages'\n | 'githubActions'\n | 'projectSetup'\n | 'vscodeExtension'\n | 'lsp'\n | 'eslint'\n | 'skills'\n | 'mcp'\n | 'infra'\n | 'cms'\n | 'repository'\n | 'chromeExtension';\n\n/** A checkbox entry of the interactive init flow. */\nexport type InitStepOption = {\n value: InitStep;\n label: string;\n hint: string;\n};\n\n/**\n * Steps shown but not pre-selected. The infrastructure installer touches the\n * machine (downloads an app, pulls Docker images) and browser extensions open external URLs\n * rather than modifying the project, so they must be an explicit choice.\n */\nexport const OPT_IN_INIT_STEPS: InitStep[] = ['infra', 'chromeExtension'];\n\n/**\n * Steps run by `intlayer init` without `--interactive`: install the packages\n * and set up the framework. Every other step has its own command\n * ({@link INIT_STEP_COMMANDS}), so nothing outside the app code is touched\n * unless asked for.\n */\nexport const DEFAULT_INIT_STEPS: InitStep[] = ['packages', 'projectSetup'];\n\n/**\n * Command running each interactive step on its own, without prompts when every\n * value is passed as a flag. Printed when `--interactive` has no terminal.\n */\nexport const INIT_STEP_COMMANDS: Record<InitStep, string> = {\n packages: 'intlayer init packages',\n projectSetup:\n 'intlayer init project [--routing <routing>] [--content <layout>] [--content-format <format>] [--message-format <format>]',\n githubActions: 'intlayer init github-actions',\n vscodeExtension: 'intlayer init vscode-extension',\n eslint: 'intlayer init eslint',\n chromeExtension: 'intlayer init extension [--browser <chrome|firefox>]',\n skills: 'intlayer init skills [--platform <platform>] [--skills <skills...>]',\n mcp: 'intlayer init mcp [--platform <platform>] [--transport <stdio|sse>]',\n lsp: 'intlayer init lsp',\n cms: 'intlayer init cms',\n repository: 'intlayer init repository',\n infra: 'intlayer init infra --mode <desktop|docker|compose>',\n};\n\n/**\n * Maps setup steps to the {@link initIntlayer} options: every step handled by\n * `initIntlayer` that is not listed is skipped. Explicit `--no-*` flags in\n * `baseOptions` still win over a listed step.\n */\nexport const getInitOptionsForSteps = (\n steps: InitStep[],\n baseOptions?: InitOptions\n): InitOptions => ({\n ...baseOptions,\n noInstallPackages:\n baseOptions?.noInstallPackages || !steps.includes('packages'),\n // The `.gitignore` entry is tied to project setup.\n noGitignore: baseOptions?.noGitignore || !steps.includes('projectSetup'),\n noGithubActions:\n baseOptions?.noGithubActions || !steps.includes('githubActions'),\n noFrameworkSetup:\n baseOptions?.noFrameworkSetup || !steps.includes('projectSetup'),\n noVscodeExtension:\n baseOptions?.noVscodeExtension || !steps.includes('vscodeExtension'),\n noLsp: baseOptions?.noLsp || !steps.includes('lsp'),\n noEslint: baseOptions?.noEslint || !steps.includes('eslint'),\n // The documentation link only matters once the project itself is set up.\n skipFinalMessage:\n baseOptions?.skipFinalMessage || !steps.includes('projectSetup'),\n});\n\n/**\n * Runs the given {@link initIntlayer} steps only (packages, project setup, CI,\n * VS Code extension, LSP, lint rules). Backs `intlayer init` and its\n * single-step subcommands.\n */\nexport const initSteps = async (\n projectRoot: string | undefined,\n steps: InitStep[],\n options?: InitOptions\n): Promise<void> => {\n await initIntlayer(\n resolveProjectRoot(projectRoot),\n getInitOptionsForSteps(steps, options)\n );\n};\n\n/**\n * Logs in to the Intlayer CMS through the browser, then stores the access-key\n * credentials in `.env` and enables the editor in the config file.\n */\nexport const initCms = async (projectRoot?: string): Promise<void> => {\n const root = resolveProjectRoot(projectRoot);\n const p = await loadPrompts();\n\n p.log.info('Opening your browser to log in to the Intlayer CMS...');\n // `exitAfter: false` keeps the process alive so the flow can finish; the\n // credentials are persisted to `.env` and the editor enabled in the config.\n await login({\n exitAfter: false,\n onCredentials: (credentials) => setupCmsCredentials(root, credentials),\n });\n};\n\n/**\n * Connects the git repository of the project to its CMS project (and sets\n * its build settings) in the browser, pre-filled with the `origin` remote.\n */\nexport const initRepository = async (projectRoot?: string): Promise<void> => {\n const root = resolveProjectRoot(projectRoot);\n const p = await loadPrompts();\n const detectedRepository = detectGitRepository(root);\n\n p.log.info(\n detectedRepository\n ? `Detected repository: ${detectedRepository.provider} ${detectedRepository.owner}/${detectedRepository.repository}`\n : 'No supported git remote detected: pick the repository in the browser.'\n );\n p.log.info('Opening your browser to connect the repository...');\n\n await setupRepository({ detectedRepository });\n};\n\n/** Explains why `--interactive` cannot run, and what to run instead. */\nconst getNoTerminalMessage = (): string =>\n [\n '`intlayer init --interactive` needs a terminal to answer its prompts (none is attached, e.g. when run by an AI agent or in CI).',\n 'Run the steps directly instead:',\n ' intlayer init (installs the packages and sets up the framework)',\n ...Object.values(INIT_STEP_COMMANDS).map((command) => ` ${command}`),\n ].join('\\n');\n\n/** Grouped checkbox entries of the interactive init flow, in display order. */\nexport const INIT_STEP_GROUPS: Record<string, InitStepOption[]> = {\n Codebase: [\n {\n value: 'packages',\n label: 'Install & upgrade packages',\n hint: 'install missing Intlayer dependencies and upgrade outdated ones',\n },\n {\n value: 'projectSetup',\n label: 'Project setup',\n hint: 'intlayer config, tsconfig, bundler plugin, middleware/proxy and providers in layout/page',\n },\n {\n value: 'githubActions',\n label: 'CI/CD (GitHub Actions)',\n hint: 'scaffold the fill and test workflows that run on every pull request (covers every project in a monorepo)',\n },\n ],\n DevTools: [\n {\n value: 'vscodeExtension',\n label: 'VS Code extension',\n hint: 'recommend the Intlayer extension',\n },\n {\n value: 'eslint',\n label: 'Lint rules (ESLint / oxlint)',\n hint: 'flag hardcoded text and dynamic calls the compiler cannot optimize',\n },\n {\n value: 'chromeExtension',\n label: 'Chrome extension',\n hint: 'for audit, debug and analysis purpose',\n },\n ],\n 'Coding assistant': [\n {\n value: 'skills',\n label: 'AI skills',\n hint: 'install the Intlayer documentation as agent skills',\n },\n {\n value: 'mcp',\n label: 'MCP server',\n hint: 'configure the Intlayer MCP server',\n },\n {\n value: 'lsp',\n label: 'Editor LSP',\n hint: 'go-to-definition from keys to .content files',\n },\n ],\n CMS: [\n {\n value: 'cms',\n label: 'CMS',\n hint: 'log in through your browser, then store the credentials in your .env',\n },\n {\n value: 'repository',\n label: 'Git repository',\n hint: 'connect the git repository to the CMS project and set its build settings (GitHub, GitLab, Bitbucket, Codeberg, Gitee)',\n },\n {\n value: 'infra',\n label: 'Infrastructure (desktop app / self-hosting)',\n hint: 'install the desktop app, or self-host with Docker (all-in-one or Compose)',\n },\n ],\n};\n\n/**\n * Locale routing choice: a `routing.mode` served through the locale proxy, or\n * `none` to leave routing to the app (`no-prefix` with the proxy disabled).\n */\nexport type LocaleRoutingChoice = RoutingMode | 'none';\n\n/** Locale routing strategies offered by the interactive init flow. */\nconst ROUTING_OPTIONS: Array<{\n value: LocaleRoutingChoice;\n label: string;\n hint: string;\n}> = [\n {\n value: 'prefix-no-default',\n label: 'Prefix all except the default locale',\n hint: '/about, /fr/about (default)',\n },\n {\n value: 'prefix-all',\n label: 'Prefix all locales',\n hint: '/en/about, /fr/about',\n },\n {\n value: 'no-prefix',\n label: 'No locale in the URL',\n hint: '/about',\n },\n {\n value: 'search-params',\n label: 'Use a search parameter',\n hint: '/about?locale=fr',\n },\n {\n value: 'none',\n label: 'No locale routing',\n hint: 'no proxy, no locale route segment — handle the locale yourself',\n },\n];\n\n/** Locale routing choices accepted by `--routing`. */\nexport const LOCALE_ROUTING_CHOICES = ROUTING_OPTIONS.map(\n (option) => option.value\n);\n\n/** Validates a `--routing` value, throwing on an unknown choice. */\nexport const parseLocaleRoutingChoice = (value: string): LocaleRoutingChoice =>\n parseChoice(value, LOCALE_ROUTING_CHOICES, '--routing');\n\n/** Maps a routing choice to the init options it sets. */\nexport const getRoutingInitOptions = (\n choice: LocaleRoutingChoice\n): Pick<InitOptions, 'routingMode' | 'enableProxy'> =>\n choice === 'none'\n ? { routingMode: 'no-prefix', enableProxy: false }\n : { routingMode: choice, enableProxy: true };\n\n/** Content declaration layouts offered by the interactive init flow. */\nconst CONTENT_LAYOUT_OPTIONS: Array<{\n value: ContentLayout;\n label: string;\n hint: string;\n}> = [\n {\n value: 'multilingual',\n label: 'Multilingual content declaration',\n hint: '/**/{fileName}.content.{ts,json} — every locale in one file',\n },\n {\n value: 'per-locale',\n label: 'Per-locale content declaration',\n hint: '/**/{fileName}.{locale}.content.{ts,json}',\n },\n {\n value: 'centralized',\n label: 'Centralized',\n hint: '/locales/{locale}.{json,po}',\n },\n {\n value: 'namespaces',\n label: 'Namespaces',\n hint: '/locales/{locale}/{namespace}.{json,po}',\n },\n];\n\n/** Labels of the content formats offered by the interactive init flow. */\nconst CONTENT_FORMAT_LABELS: Record<ContentFormat, string> = {\n ts: 'TypeScript (.ts)',\n json: 'JSON (.json)',\n po: 'Gettext (.po)',\n};\n\n/** Labels of the JSON catalog message formats, in display order. */\nconst CATALOG_MESSAGE_FORMAT_OPTIONS: Record<\n CatalogMessageFormat,\n { label: string; hint: string }\n> = {\n icu: { label: 'ICU', hint: '{count, plural, one {# item} other {# items}}' },\n i18next: { label: 'i18next', hint: '{{count}} item, key_one / key_other' },\n 'vue-i18n': { label: 'vue-i18n', hint: '{count} item | {count} items' },\n intlayer: { label: 'Intlayer', hint: 'Intlayer dictionary content' },\n};\n\n/** Content layouts accepted by `--content`. */\nexport const CONTENT_LAYOUT_CHOICES = CONTENT_LAYOUT_OPTIONS.map(\n (option) => option.value\n);\n\n/** Validates a `--content` value, throwing on an unknown layout. */\nexport const parseContentLayoutChoice = (value: string): ContentLayout =>\n parseChoice(value, CONTENT_LAYOUT_CHOICES, '--content');\n\n/** Init options set by the content layout questions / flags. */\ntype ContentInitOptions = Pick<\n InitOptions,\n 'contentLayout' | 'contentFormat' | 'contentMessageFormat'\n>;\n\n/** Whether a layout + format pair produces a JSON catalog (sync plugin). */\nconst isJsonCatalog = (layout: ContentLayout, format: ContentFormat): boolean =>\n (layout === 'centralized' || layout === 'namespaces') && format === 'json';\n\n/**\n * Validates `--content` / `--content-format` / `--message-format` and maps\n * them to the init options. The format must be one the layout accepts, and the\n * message format only applies to JSON catalogs.\n */\nexport const getContentInitOptions = (\n layoutValue?: string,\n formatValue?: string,\n messageFormatValue?: string\n): ContentInitOptions => {\n if (!layoutValue) {\n if (formatValue || messageFormatValue) {\n throw new Error(\n '--content-format and --message-format require --content.'\n );\n }\n return {};\n }\n\n const contentLayout = parseContentLayoutChoice(layoutValue);\n const contentFormat = formatValue\n ? parseChoice(\n formatValue,\n CONTENT_FORMATS_BY_LAYOUT[contentLayout],\n '--content-format'\n )\n : undefined;\n\n if (!messageFormatValue) return { contentLayout, contentFormat };\n\n // Catalog layouts default to JSON.\n if (!isJsonCatalog(contentLayout, contentFormat ?? 'json')) {\n throw new Error(\n '--message-format only applies to JSON catalogs (--content centralized | namespaces with json).'\n );\n }\n\n return {\n contentLayout,\n contentFormat,\n contentMessageFormat: parseChoice(\n messageFormatValue,\n CATALOG_MESSAGE_FORMATS,\n '--message-format'\n ),\n };\n};\n\n/** Known ESLint and oxlint configuration file names. */\nexport const ESLINT_CONFIG_FILES = [\n 'eslint.config.js',\n 'eslint.config.mjs',\n 'eslint.config.cjs',\n 'eslint.config.ts',\n 'eslint.config.mts',\n 'eslint.config.cts',\n '.eslintrc.js',\n '.eslintrc.cjs',\n '.eslintrc.yaml',\n '.eslintrc.yml',\n '.eslintrc.json',\n '.eslintrc',\n '.oxlintrc.json',\n];\n\n/**\n * Checks whether ESLint or a compatible linter (oxlint) is installed or\n * configured in the project.\n */\nexport const isEslintInstalled = (\n dependencies: Record<string, string>,\n root?: string\n): boolean => {\n if (hasLintTooling(dependencies)) return true;\n if (dependencies.eslint || dependencies.oxlint) return true;\n\n if (root) {\n return ESLINT_CONFIG_FILES.some((file) => existsSync(join(root, file)));\n }\n\n return false;\n};\n\n/**\n * Computes the initial setup steps selected by default in the interactive prompt.\n * Steps like infrastructure and browser extension require opt-in, while\n * eslint is preselected only if installed on the project.\n */\nexport const getInitialInitSteps = (\n dependencies: Record<string, string>,\n root?: string\n): InitStep[] => {\n const isEslintPresent = isEslintInstalled(dependencies, root);\n\n return Object.values(INIT_STEP_GROUPS)\n .flat()\n .map((option) => option.value)\n .filter((step) => {\n if (OPT_IN_INIT_STEPS.includes(step)) return false;\n if (step === 'eslint' && !isEslintPresent) return false;\n return true;\n });\n};\n\n/** Reads the merged dependencies of the project at `root`. */\nexport const getProjectDependencies = (\n root: string\n): Record<string, string> => {\n try {\n const packageJsonPath = join(root, 'package.json');\n if (!existsSync(packageJsonPath)) return {};\n const { dependencies = {}, devDependencies = {} } = JSON.parse(\n readFileSync(packageJsonPath, 'utf-8')\n );\n return { ...dependencies, ...devDependencies };\n } catch {\n return {};\n }\n};\n\n/**\n * Runs `init` in interactive mode: prompts the user with a checkbox of setup\n * steps, then forwards the selection to {@link initIntlayer} (packages, GitHub\n * Actions, VS Code extension, LSP) and runs the dedicated skills/MCP installers\n * for the steps that own their own prompts. The `.gitignore` entry is not\n * offered as a checkbox — it is always added (unless `--no-gitignore` is set).\n */\nconst runInteractiveInit = async (\n root: string,\n baseOptions?: InitOptions\n): Promise<void> => {\n const p = await loadPrompts();\n\n p.intro('Initialize Intlayer');\n\n const projectDependencies = getProjectDependencies(root);\n\n const selected = await p.groupMultiselect<InitStep>({\n message: 'Select what you want to set up:',\n options: INIT_STEP_GROUPS,\n initialValues: getInitialInitSteps(projectDependencies, root),\n required: false,\n });\n\n if (p.isCancel(selected)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n const steps = selected as InitStep[];\n\n // Compat i18n library detection — never asked, always derived from the\n // installed packages. `detectMissingIntlayerPackages` reads the very same\n // dependency map to schedule the compat adapter, the sync plugin and the\n // catalog template, so a project without any of those packages is simply set\n // up on Intlayer alone.\n const detectedCompatLibraries =\n detectCompatI18nLibraries(projectDependencies);\n const hasCompatLib = detectedCompatLibraries.length > 0;\n\n if (hasCompatLib) {\n p.log.info(\n `Detected existing i18n ${detectedCompatLibraries.length > 1 ? 'libraries' : 'library'}: ${detectedCompatLibraries.join(', ')} — the matching Intlayer compat adapter and catalog sync will be set up.`\n );\n }\n\n // Locale routing → `routing.mode` + `routing.enableProxy` in the config, and\n // the route segment the framework scaffolding creates. Only asked for web\n // frontends; projects without URL routing (backend, React Native / Expo) keep\n // only `routing.storage` in a freshly created config. Skipped for compat\n // i18n libraries, which keep their own routing.\n let routingOptions: Pick<InitOptions, 'routingMode' | 'enableProxy'> = {};\n\n if (\n steps.includes('projectSetup') &&\n baseOptions?.routingMode === undefined &&\n !hasCompatLib &&\n hasUrlRoutingFramework(projectDependencies)\n ) {\n const selectedRouting = await p.select<LocaleRoutingChoice>({\n message: 'How should the locale appear in your URLs?',\n options: ROUTING_OPTIONS,\n initialValue: 'prefix-no-default',\n });\n\n if (p.isCancel(selectedRouting)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n routingOptions = getRoutingInitOptions(selectedRouting);\n }\n\n // Content layout → `compiler.output` (+ `dictionary.locale`) for `.content`\n // files, or the syncJSON / syncPO plugin for catalogs. Skipped for compat\n // i18n libraries, which keep their own catalogs.\n let contentOptions: ContentInitOptions = {};\n\n if (\n steps.includes('projectSetup') &&\n baseOptions?.contentLayout === undefined &&\n !hasCompatLib\n ) {\n const contentLayout = await p.select<ContentLayout>({\n message: 'How do you want to declare your content?',\n options: CONTENT_LAYOUT_OPTIONS,\n initialValue: 'multilingual',\n });\n\n if (p.isCancel(contentLayout)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n const acceptedFormats = CONTENT_FORMATS_BY_LAYOUT[contentLayout];\n const hasTypeScript = existsSync(join(root, 'tsconfig.json'));\n\n const contentFormat = await p.select<ContentFormat>({\n message: 'Which format for your content?',\n options: acceptedFormats.map((format) => ({\n value: format,\n label: CONTENT_FORMAT_LABELS[format],\n })),\n initialValue:\n acceptedFormats.includes('ts') && !hasTypeScript\n ? 'json'\n : acceptedFormats[0],\n });\n\n if (p.isCancel(contentFormat)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n contentOptions = { contentLayout, contentFormat };\n\n // JSON catalogs carry a message syntax (plurals, interpolation…).\n if (isJsonCatalog(contentLayout, contentFormat)) {\n const contentMessageFormat = await p.select<CatalogMessageFormat>({\n message: 'Which message format do your JSON catalogs use?',\n options: CATALOG_MESSAGE_FORMATS.map((messageFormat) => ({\n value: messageFormat,\n ...CATALOG_MESSAGE_FORMAT_OPTIONS[messageFormat],\n })),\n initialValue: CATALOG_MESSAGE_FORMATS[0],\n });\n\n if (p.isCancel(contentMessageFormat)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n contentOptions = { ...contentOptions, contentMessageFormat };\n }\n }\n\n const options: InitOptions = {\n ...getInitOptionsForSteps(steps, {\n ...baseOptions,\n ...routingOptions,\n ...contentOptions,\n }),\n skipFinalMessage: true,\n };\n\n const { guideUrl } = await initIntlayer(root, options);\n\n // Skills ask for the platform after the skill selection; MCP reuses it.\n const skillsPlatform = steps.includes('skills')\n ? await initSkills(root)\n : undefined;\n\n if (steps.includes('mcp')) {\n await initMCP(root, { platform: skillsPlatform });\n }\n\n // Delegated to the hosted install script, which owns its own menu.\n if (steps.includes('infra')) {\n await initInfra();\n }\n\n if (steps.includes('chromeExtension')) {\n await initChromeExtension();\n }\n\n // CMS / visual editor runs last: the browser login persists the access-key\n // credentials to `.env` and enables the editor in the config file. Kept last\n // so the browser flow does not interrupt setup.\n if (steps.includes('cms')) {\n await initCms(root);\n }\n\n // After the CMS login, so the browser is already signed in\n if (steps.includes('repository')) {\n await initRepository(root);\n }\n\n p.outro('Intlayer initialization complete');\n\n if (guideUrl) {\n logInitSuccessMessage(guideUrl);\n }\n};\n\n/**\n * `intlayer init`: installs the packages and sets up the framework, or, with\n * `interactive`, lets the user pick every setup step. `--interactive` needs a\n * terminal; without one it fails and lists the single-step commands instead.\n */\nexport const init = async (\n projectRoot?: string,\n options?: InitOptions,\n interactive?: boolean\n) => {\n if (!interactive) {\n await initSteps(projectRoot, DEFAULT_INIT_STEPS, options);\n return;\n }\n\n if (!isInteractiveTerminal()) {\n const p = await loadPrompts();\n\n p.log.error(getNoTerminalMessage());\n process.exitCode = 1;\n return;\n }\n\n await runInteractiveInit(resolveProjectRoot(projectRoot), options);\n};\n"],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_utils_openBrowser = require('./utils/openBrowser.cjs');
3
3
  const require_loadPrompts = require('./loadPrompts.cjs');
4
+ const require_utils_isInteractiveTerminal = require('./utils/isInteractiveTerminal.cjs');
5
+ const require_utils_parseChoice = require('./utils/parseChoice.cjs');
4
6
 
5
7
  //#region src/initChromeExtension.ts
6
8
  const CHROME_EXTENSION_URL = "https://chromewebstore.google.com/detail/intlayer_i18n_scanner/pmlehcgmjmfimmjnembihbakhnheiabc";
@@ -14,15 +16,33 @@ const BROWSER_EXTENSION_OPTIONS = [{
14
16
  label: "Mozilla Firefox",
15
17
  hint: MOZILLA_EXTENSION_URL
16
18
  }];
17
- const initChromeExtension = async () => {
19
+ /** Browsers accepted by `intlayer init extension --browser`. */
20
+ const EXTENSION_BROWSERS = ["chrome", "firefox"];
21
+ /** Store page of the Intlayer extension, per browser. */
22
+ const EXTENSION_URL_BY_BROWSER = {
23
+ chrome: CHROME_EXTENSION_URL,
24
+ firefox: MOZILLA_EXTENSION_URL
25
+ };
26
+ /** Validates the `--browser` values, ignoring case. */
27
+ const parseExtensionBrowsers = (values) => values.flatMap((value) => value.split(",")).filter((value) => value.trim() !== "").map((value) => require_utils_parseChoice.parseChoice(value, EXTENSION_BROWSERS, "--browser"));
28
+ /**
29
+ * Opens the store page of the Intlayer browser extension. The browsers are
30
+ * prompted for unless given; without a terminal (AI agents, CI) the store
31
+ * links are only printed, since the install needs a person anyway.
32
+ */
33
+ const initChromeExtension = async (options = {}) => {
18
34
  const p = await require_loadPrompts.loadPrompts();
19
- const selectedUrls = await p.multiselect({
35
+ if (!options.browsers && !require_utils_isInteractiveTerminal.isInteractiveTerminal()) {
36
+ p.log.info(`Install the Intlayer browser extension:\n${BROWSER_EXTENSION_OPTIONS.map(({ label, value }) => ` ${label}: ${value}`).join("\n")}`);
37
+ return;
38
+ }
39
+ const selectedUrls = options.browsers ? options.browsers.map((browser) => EXTENSION_URL_BY_BROWSER[browser]) : await p.multiselect({
20
40
  message: "Select browser extension(s) to install:",
21
41
  options: BROWSER_EXTENSION_OPTIONS,
22
42
  required: false
23
43
  });
24
44
  if (p.isCancel(selectedUrls)) return;
25
- if (Array.isArray(selectedUrls) && selectedUrls.length > 0) for (const url of selectedUrls) {
45
+ for (const url of selectedUrls) {
26
46
  p.log.info(`Opening ${url} in your browser...`);
27
47
  require_utils_openBrowser.openBrowser(url);
28
48
  }
@@ -31,6 +51,9 @@ const initChromeExtension = async () => {
31
51
  //#endregion
32
52
  exports.BROWSER_EXTENSION_OPTIONS = BROWSER_EXTENSION_OPTIONS;
33
53
  exports.CHROME_EXTENSION_URL = CHROME_EXTENSION_URL;
54
+ exports.EXTENSION_BROWSERS = EXTENSION_BROWSERS;
55
+ exports.EXTENSION_URL_BY_BROWSER = EXTENSION_URL_BY_BROWSER;
34
56
  exports.MOZILLA_EXTENSION_URL = MOZILLA_EXTENSION_URL;
35
57
  exports.initChromeExtension = initChromeExtension;
58
+ exports.parseExtensionBrowsers = parseExtensionBrowsers;
36
59
  //# sourceMappingURL=initChromeExtension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"initChromeExtension.cjs","names":["loadPrompts"],"sources":["../../src/initChromeExtension.ts"],"sourcesContent":["import { loadPrompts } from './loadPrompts';\nimport { openBrowser } from './utils/openBrowser';\n\nexport const CHROME_EXTENSION_URL =\n 'https://chromewebstore.google.com/detail/intlayer_i18n_scanner/pmlehcgmjmfimmjnembihbakhnheiabc';\n\nexport const MOZILLA_EXTENSION_URL =\n 'https://addons.mozilla.org/en-US/firefox/addon/intlayer-i18n-scanner/';\n\nexport const BROWSER_EXTENSION_OPTIONS = [\n {\n value: CHROME_EXTENSION_URL,\n label: 'Chrome',\n hint: CHROME_EXTENSION_URL,\n },\n {\n value: MOZILLA_EXTENSION_URL,\n label: 'Mozilla Firefox',\n hint: MOZILLA_EXTENSION_URL,\n },\n];\n\nexport const initChromeExtension = async () => {\n const p = await loadPrompts();\n\n const selectedUrls = await p.multiselect({\n message: 'Select browser extension(s) to install:',\n options: BROWSER_EXTENSION_OPTIONS,\n required: false,\n });\n\n if (p.isCancel(selectedUrls)) {\n return;\n }\n\n if (Array.isArray(selectedUrls) && selectedUrls.length > 0) {\n for (const url of selectedUrls) {\n p.log.info(`Opening ${url} in your browser...`);\n openBrowser(url);\n }\n }\n};\n"],"mappings":";;;;;AAGA,MAAa,uBACX;AAEF,MAAa,wBACX;AAEF,MAAa,4BAA4B,CACvC;CACE,OAAO;CACP,OAAO;CACP,MAAM;AACR,GACA;CACE,OAAO;CACP,OAAO;CACP,MAAM;AACR,CACF;AAEA,MAAa,sBAAsB,YAAY;CAC7C,MAAM,IAAI,MAAMA,gCAAY;CAE5B,MAAM,eAAe,MAAM,EAAE,YAAY;EACvC,SAAS;EACT,SAAS;EACT,UAAU;CACZ,CAAC;CAED,IAAI,EAAE,SAAS,YAAY,GACzB;CAGF,IAAI,MAAM,QAAQ,YAAY,KAAK,aAAa,SAAS,GACvD,KAAK,MAAM,OAAO,cAAc;EAC9B,EAAE,IAAI,KAAK,WAAW,IAAI,oBAAoB;EAC9C,sCAAY,GAAG;CACjB;AAEJ"}
1
+ {"version":3,"file":"initChromeExtension.cjs","names":["parseChoice","loadPrompts","isInteractiveTerminal"],"sources":["../../src/initChromeExtension.ts"],"sourcesContent":["import { loadPrompts } from './loadPrompts';\nimport { isInteractiveTerminal } from './utils/isInteractiveTerminal';\nimport { openBrowser } from './utils/openBrowser';\nimport { parseChoice } from './utils/parseChoice';\n\nexport const CHROME_EXTENSION_URL =\n 'https://chromewebstore.google.com/detail/intlayer_i18n_scanner/pmlehcgmjmfimmjnembihbakhnheiabc';\n\nexport const MOZILLA_EXTENSION_URL =\n 'https://addons.mozilla.org/en-US/firefox/addon/intlayer-i18n-scanner/';\n\nexport const BROWSER_EXTENSION_OPTIONS = [\n {\n value: CHROME_EXTENSION_URL,\n label: 'Chrome',\n hint: CHROME_EXTENSION_URL,\n },\n {\n value: MOZILLA_EXTENSION_URL,\n label: 'Mozilla Firefox',\n hint: MOZILLA_EXTENSION_URL,\n },\n];\n\n/** Browsers the Intlayer extension is published for. */\nexport type ExtensionBrowser = 'chrome' | 'firefox';\n\n/** Browsers accepted by `intlayer init extension --browser`. */\nexport const EXTENSION_BROWSERS: ExtensionBrowser[] = ['chrome', 'firefox'];\n\n/** Store page of the Intlayer extension, per browser. */\nexport const EXTENSION_URL_BY_BROWSER: Record<ExtensionBrowser, string> = {\n chrome: CHROME_EXTENSION_URL,\n firefox: MOZILLA_EXTENSION_URL,\n};\n\n/** Validates the `--browser` values, ignoring case. */\nexport const parseExtensionBrowsers = (values: string[]): ExtensionBrowser[] =>\n values\n .flatMap((value) => value.split(','))\n .filter((value) => value.trim() !== '')\n .map((value) => parseChoice(value, EXTENSION_BROWSERS, '--browser'));\n\n/** Options of {@link initChromeExtension}. */\nexport type InitChromeExtensionOptions = {\n /** Browsers to open the store page for, skipping the prompt. */\n browsers?: ExtensionBrowser[];\n};\n\n/**\n * Opens the store page of the Intlayer browser extension. The browsers are\n * prompted for unless given; without a terminal (AI agents, CI) the store\n * links are only printed, since the install needs a person anyway.\n */\nexport const initChromeExtension = async (\n options: InitChromeExtensionOptions = {}\n) => {\n const p = await loadPrompts();\n\n if (!options.browsers && !isInteractiveTerminal()) {\n p.log.info(\n `Install the Intlayer browser extension:\\n${BROWSER_EXTENSION_OPTIONS.map(\n ({ label, value }) => ` ${label}: ${value}`\n ).join('\\n')}`\n );\n return;\n }\n\n const selectedUrls = options.browsers\n ? options.browsers.map((browser) => EXTENSION_URL_BY_BROWSER[browser])\n : await p.multiselect({\n message: 'Select browser extension(s) to install:',\n options: BROWSER_EXTENSION_OPTIONS,\n required: false,\n });\n\n if (p.isCancel(selectedUrls)) {\n return;\n }\n\n for (const url of selectedUrls) {\n p.log.info(`Opening ${url} in your browser...`);\n openBrowser(url);\n }\n};\n"],"mappings":";;;;;;;AAKA,MAAa,uBACX;AAEF,MAAa,wBACX;AAEF,MAAa,4BAA4B,CACvC;CACE,OAAO;CACP,OAAO;CACP,MAAM;AACR,GACA;CACE,OAAO;CACP,OAAO;CACP,MAAM;AACR,CACF;;AAMA,MAAa,qBAAyC,CAAC,UAAU,SAAS;;AAG1E,MAAa,2BAA6D;CACxE,QAAQ;CACR,SAAS;AACX;;AAGA,MAAa,0BAA0B,WACrC,OACG,SAAS,UAAU,MAAM,MAAM,GAAG,CAAC,CAAC,CACpC,QAAQ,UAAU,MAAM,KAAK,MAAM,EAAE,CAAC,CACtC,KAAK,UAAUA,sCAAY,OAAO,oBAAoB,WAAW,CAAC;;;;;;AAavE,MAAa,sBAAsB,OACjC,UAAsC,CAAC,MACpC;CACH,MAAM,IAAI,MAAMC,gCAAY;CAE5B,IAAI,CAAC,QAAQ,YAAY,CAACC,0DAAsB,GAAG;EACjD,EAAE,IAAI,KACJ,4CAA4C,0BAA0B,KACnE,EAAE,OAAO,YAAY,KAAK,MAAM,IAAI,OACvC,CAAC,CAAC,KAAK,IAAI,GACb;EACA;CACF;CAEA,MAAM,eAAe,QAAQ,WACzB,QAAQ,SAAS,KAAK,YAAY,yBAAyB,QAAQ,IACnE,MAAM,EAAE,YAAY;EAClB,SAAS;EACT,SAAS;EACT,UAAU;CACZ,CAAC;CAEL,IAAI,EAAE,SAAS,YAAY,GACzB;CAGF,KAAK,MAAM,OAAO,cAAc;EAC9B,EAAE,IAAI,KAAK,WAAW,IAAI,oBAAoB;EAC9C,sCAAY,GAAG;CACjB;AACF"}
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_loadPrompts = require('./loadPrompts.cjs');
3
+ const require_utils_isInteractiveTerminal = require('./utils/isInteractiveTerminal.cjs');
3
4
  let node_path = require("node:path");
4
5
  let node_child_process = require("node:child_process");
5
6
  let node_os = require("node:os");
@@ -65,6 +66,11 @@ const runInstaller = (command, args) => new Promise((resolve, reject) => {
65
66
  */
66
67
  const initInfra = async (options = {}) => {
67
68
  const p = await require_loadPrompts.loadPrompts();
69
+ if (!options.mode && !require_utils_isInteractiveTerminal.isInteractiveTerminal()) {
70
+ p.log.error(`No terminal to show the setup menu. Pass the mode explicitly: intlayer init infra --mode <${INFRA_MODES.join(" | ")}>`);
71
+ process.exitCode = 1;
72
+ return;
73
+ }
68
74
  const runner = getInstallerRunner();
69
75
  const scriptUrl = options.scriptUrl ?? runner.url;
70
76
  const spinner = p.spinner();
@@ -1 +1 @@
1
- {"version":3,"file":"initInfra.cjs","names":["spawn","loadPrompts","mkdtemp","join","tmpdir","writeFile","rm"],"sources":["../../src/initInfra.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { loadPrompts } from './loadPrompts';\n\n/** Setup modes understood by the hosted installer. */\nexport const INFRA_MODES = ['desktop', 'docker', 'compose'] as const;\n\nexport type InfraMode = (typeof INFRA_MODES)[number];\n\n/**\n * The hosted installers are the single source of truth for the infrastructure\n * setup flow (desktop app, all-in-one container, Compose stack). The CLI runs\n * them rather than re-implementing the same steps in JavaScript.\n */\nexport const INSTALL_SCRIPT_URL = 'https://intlayer.org/install.sh';\nexport const INSTALL_SCRIPT_URL_WINDOWS = 'https://intlayer.org/install.ps1';\n\nexport type InitInfraOptions = {\n /** Skip the interactive menu and run this mode directly. */\n mode?: InfraMode;\n /** Installer URL override (forks, staging). Defaults to the platform's script. */\n scriptUrl?: string;\n};\n\n/** How to fetch and execute the installer on the current platform. */\ntype InstallerRunner = {\n url: string;\n fileName: string;\n /** Builds the command and arguments that execute the downloaded script. */\n command: (scriptPath: string, mode?: InfraMode) => [string, string[]];\n};\n\nconst POSIX_RUNNER: InstallerRunner = {\n url: INSTALL_SCRIPT_URL,\n fileName: 'install.sh',\n command: (scriptPath, mode) => [\n 'sh',\n [scriptPath, ...(mode ? ['--mode', mode] : [])],\n ],\n};\n\nconst WINDOWS_RUNNER: InstallerRunner = {\n url: INSTALL_SCRIPT_URL_WINDOWS,\n fileName: 'install.ps1',\n command: (scriptPath, mode) => [\n 'powershell',\n [\n '-NoProfile',\n '-ExecutionPolicy',\n 'Bypass',\n '-File',\n scriptPath,\n ...(mode ? ['-Mode', mode] : []),\n ],\n ],\n};\n\nconst getInstallerRunner = (): InstallerRunner =>\n process.platform === 'win32' ? WINDOWS_RUNNER : POSIX_RUNNER;\n\n/**\n * Validates a user-provided mode against {@link INFRA_MODES}.\n *\n * @throws When the value is not a known mode.\n */\nexport const parseInfraMode = (value: string): InfraMode => {\n if ((INFRA_MODES as readonly string[]).includes(value)) {\n return value as InfraMode;\n }\n\n throw new Error(\n `Unknown infra mode \"${value}\". Expected one of: ${INFRA_MODES.join(', ')}`\n );\n};\n\n/**\n * Runs the installer with the terminal attached, so its own prompts and\n * progress bars reach the user unchanged.\n *\n * @returns The script's exit code.\n */\nconst runInstaller = (command: string, args: string[]): Promise<number> =>\n new Promise((resolve, reject) => {\n const child = spawn(command, args, { stdio: 'inherit' });\n\n child.on('error', reject);\n child.on('close', (code) => resolve(code ?? 1));\n });\n\n/**\n * Downloads the hosted installer and runs it: desktop app, all-in-one Docker\n * container or Docker Compose stack, chosen interactively unless `mode` is set.\n *\n * Exposed as `intlayer init infra` and as a step of `intlayer init --interactive`.\n */\nexport const initInfra = async (\n options: InitInfraOptions = {}\n): Promise<void> => {\n const p = await loadPrompts();\n const runner = getInstallerRunner();\n const scriptUrl = options.scriptUrl ?? runner.url;\n\n const spinner = p.spinner();\n spinner.start(`Fetching ${scriptUrl}`);\n\n let script: string;\n\n try {\n const response = await fetch(scriptUrl);\n\n if (!response.ok) {\n throw new Error(`${response.status} ${response.statusText}`);\n }\n\n script = await response.text();\n } catch (error) {\n spinner.stop('Could not download the installer');\n p.log.error(\n `${(error as Error).message}\\nRun it directly: ${\n process.platform === 'win32'\n ? `irm ${scriptUrl} | iex`\n : `curl -fsSL ${scriptUrl} | sh`\n }`\n );\n process.exitCode = 1;\n return;\n }\n\n spinner.stop('Installer downloaded');\n\n const directory = await mkdtemp(join(tmpdir(), 'intlayer-install-'));\n const scriptPath = join(directory, runner.fileName);\n\n try {\n await writeFile(scriptPath, script, { mode: 0o700 });\n\n const [command, args] = runner.command(scriptPath, options.mode);\n const exitCode = await runInstaller(command, args);\n\n if (exitCode !== 0) {\n process.exitCode = exitCode;\n }\n } finally {\n await rm(directory, { recursive: true, force: true });\n }\n};\n"],"mappings":";;;;;;;;;AAOA,MAAa,cAAc;CAAC;CAAW;CAAU;AAAS;;;;;;AAS1D,MAAa,qBAAqB;AAClC,MAAa,6BAA6B;AAiB1C,MAAM,eAAgC;CACpC,KAAK;CACL,UAAU;CACV,UAAU,YAAY,SAAS,CAC7B,MACA,CAAC,YAAY,GAAI,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAE,CAChD;AACF;AAEA,MAAM,iBAAkC;CACtC,KAAK;CACL,UAAU;CACV,UAAU,YAAY,SAAS,CAC7B,cACA;EACE;EACA;EACA;EACA;EACA;EACA,GAAI,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;CAChC,CACF;AACF;AAEA,MAAM,2BACJ,QAAQ,aAAa,UAAU,iBAAiB;;;;;;AAOlD,MAAa,kBAAkB,UAA6B;CAC1D,IAAK,YAAkC,SAAS,KAAK,GACnD,OAAO;CAGT,MAAM,IAAI,MACR,uBAAuB,MAAM,sBAAsB,YAAY,KAAK,IAAI,GAC1E;AACF;;;;;;;AAQA,MAAM,gBAAgB,SAAiB,SACrC,IAAI,SAAS,SAAS,WAAW;CAC/B,MAAM,YAAQA,0BAAM,SAAS,MAAM,EAAE,OAAO,UAAU,CAAC;CAEvD,MAAM,GAAG,SAAS,MAAM;CACxB,MAAM,GAAG,UAAU,SAAS,QAAQ,QAAQ,CAAC,CAAC;AAChD,CAAC;;;;;;;AAQH,MAAa,YAAY,OACvB,UAA4B,CAAC,MACX;CAClB,MAAM,IAAI,MAAMC,gCAAY;CAC5B,MAAM,SAAS,mBAAmB;CAClC,MAAM,YAAY,QAAQ,aAAa,OAAO;CAE9C,MAAM,UAAU,EAAE,QAAQ;CAC1B,QAAQ,MAAM,YAAY,WAAW;CAErC,IAAI;CAEJ,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,SAAS;EAEtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,SAAS,YAAY;EAG7D,SAAS,MAAM,SAAS,KAAK;CAC/B,SAAS,OAAO;EACd,QAAQ,KAAK,kCAAkC;EAC/C,EAAE,IAAI,MACJ,GAAI,MAAgB,QAAQ,qBAC1B,QAAQ,aAAa,UACjB,OAAO,UAAU,UACjB,cAAc,UAAU,QAEhC;EACA,QAAQ,WAAW;EACnB;CACF;CAEA,QAAQ,KAAK,sBAAsB;CAEnC,MAAM,YAAY,UAAMC,8BAAQC,oBAAKC,gBAAO,GAAG,mBAAmB,CAAC;CACnE,MAAM,iBAAaD,gBAAK,WAAW,OAAO,QAAQ;CAElD,IAAI;EACF,UAAME,4BAAU,YAAY,QAAQ,EAAE,MAAM,IAAM,CAAC;EAEnD,MAAM,CAAC,SAAS,QAAQ,OAAO,QAAQ,YAAY,QAAQ,IAAI;EAC/D,MAAM,WAAW,MAAM,aAAa,SAAS,IAAI;EAEjD,IAAI,aAAa,GACf,QAAQ,WAAW;CAEvB,UAAU;EACR,UAAMC,qBAAG,WAAW;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CACtD;AACF"}
1
+ {"version":3,"file":"initInfra.cjs","names":["spawn","loadPrompts","isInteractiveTerminal","mkdtemp","join","tmpdir","writeFile","rm"],"sources":["../../src/initInfra.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { loadPrompts } from './loadPrompts';\nimport { isInteractiveTerminal } from './utils/isInteractiveTerminal';\n\n/** Setup modes understood by the hosted installer. */\nexport const INFRA_MODES = ['desktop', 'docker', 'compose'] as const;\n\nexport type InfraMode = (typeof INFRA_MODES)[number];\n\n/**\n * The hosted installers are the single source of truth for the infrastructure\n * setup flow (desktop app, all-in-one container, Compose stack). The CLI runs\n * them rather than re-implementing the same steps in JavaScript.\n */\nexport const INSTALL_SCRIPT_URL = 'https://intlayer.org/install.sh';\nexport const INSTALL_SCRIPT_URL_WINDOWS = 'https://intlayer.org/install.ps1';\n\nexport type InitInfraOptions = {\n /** Skip the interactive menu and run this mode directly. */\n mode?: InfraMode;\n /** Installer URL override (forks, staging). Defaults to the platform's script. */\n scriptUrl?: string;\n};\n\n/** How to fetch and execute the installer on the current platform. */\ntype InstallerRunner = {\n url: string;\n fileName: string;\n /** Builds the command and arguments that execute the downloaded script. */\n command: (scriptPath: string, mode?: InfraMode) => [string, string[]];\n};\n\nconst POSIX_RUNNER: InstallerRunner = {\n url: INSTALL_SCRIPT_URL,\n fileName: 'install.sh',\n command: (scriptPath, mode) => [\n 'sh',\n [scriptPath, ...(mode ? ['--mode', mode] : [])],\n ],\n};\n\nconst WINDOWS_RUNNER: InstallerRunner = {\n url: INSTALL_SCRIPT_URL_WINDOWS,\n fileName: 'install.ps1',\n command: (scriptPath, mode) => [\n 'powershell',\n [\n '-NoProfile',\n '-ExecutionPolicy',\n 'Bypass',\n '-File',\n scriptPath,\n ...(mode ? ['-Mode', mode] : []),\n ],\n ],\n};\n\nconst getInstallerRunner = (): InstallerRunner =>\n process.platform === 'win32' ? WINDOWS_RUNNER : POSIX_RUNNER;\n\n/**\n * Validates a user-provided mode against {@link INFRA_MODES}.\n *\n * @throws When the value is not a known mode.\n */\nexport const parseInfraMode = (value: string): InfraMode => {\n if ((INFRA_MODES as readonly string[]).includes(value)) {\n return value as InfraMode;\n }\n\n throw new Error(\n `Unknown infra mode \"${value}\". Expected one of: ${INFRA_MODES.join(', ')}`\n );\n};\n\n/**\n * Runs the installer with the terminal attached, so its own prompts and\n * progress bars reach the user unchanged.\n *\n * @returns The script's exit code.\n */\nconst runInstaller = (command: string, args: string[]): Promise<number> =>\n new Promise((resolve, reject) => {\n const child = spawn(command, args, { stdio: 'inherit' });\n\n child.on('error', reject);\n child.on('close', (code) => resolve(code ?? 1));\n });\n\n/**\n * Downloads the hosted installer and runs it: desktop app, all-in-one Docker\n * container or Docker Compose stack, chosen interactively unless `mode` is set.\n *\n * Exposed as `intlayer init infra` and as a step of `intlayer init --interactive`.\n */\nexport const initInfra = async (\n options: InitInfraOptions = {}\n): Promise<void> => {\n const p = await loadPrompts();\n\n // The installer's menu reads from the terminal: without one it cannot be\n // answered, so the mode has to be passed explicitly.\n if (!options.mode && !isInteractiveTerminal()) {\n p.log.error(\n `No terminal to show the setup menu. Pass the mode explicitly: intlayer init infra --mode <${INFRA_MODES.join(' | ')}>`\n );\n process.exitCode = 1;\n return;\n }\n\n const runner = getInstallerRunner();\n const scriptUrl = options.scriptUrl ?? runner.url;\n\n const spinner = p.spinner();\n spinner.start(`Fetching ${scriptUrl}`);\n\n let script: string;\n\n try {\n const response = await fetch(scriptUrl);\n\n if (!response.ok) {\n throw new Error(`${response.status} ${response.statusText}`);\n }\n\n script = await response.text();\n } catch (error) {\n spinner.stop('Could not download the installer');\n p.log.error(\n `${(error as Error).message}\\nRun it directly: ${\n process.platform === 'win32'\n ? `irm ${scriptUrl} | iex`\n : `curl -fsSL ${scriptUrl} | sh`\n }`\n );\n process.exitCode = 1;\n return;\n }\n\n spinner.stop('Installer downloaded');\n\n const directory = await mkdtemp(join(tmpdir(), 'intlayer-install-'));\n const scriptPath = join(directory, runner.fileName);\n\n try {\n await writeFile(scriptPath, script, { mode: 0o700 });\n\n const [command, args] = runner.command(scriptPath, options.mode);\n const exitCode = await runInstaller(command, args);\n\n if (exitCode !== 0) {\n process.exitCode = exitCode;\n }\n } finally {\n await rm(directory, { recursive: true, force: true });\n }\n};\n"],"mappings":";;;;;;;;;;AAQA,MAAa,cAAc;CAAC;CAAW;CAAU;AAAS;;;;;;AAS1D,MAAa,qBAAqB;AAClC,MAAa,6BAA6B;AAiB1C,MAAM,eAAgC;CACpC,KAAK;CACL,UAAU;CACV,UAAU,YAAY,SAAS,CAC7B,MACA,CAAC,YAAY,GAAI,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAE,CAChD;AACF;AAEA,MAAM,iBAAkC;CACtC,KAAK;CACL,UAAU;CACV,UAAU,YAAY,SAAS,CAC7B,cACA;EACE;EACA;EACA;EACA;EACA;EACA,GAAI,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;CAChC,CACF;AACF;AAEA,MAAM,2BACJ,QAAQ,aAAa,UAAU,iBAAiB;;;;;;AAOlD,MAAa,kBAAkB,UAA6B;CAC1D,IAAK,YAAkC,SAAS,KAAK,GACnD,OAAO;CAGT,MAAM,IAAI,MACR,uBAAuB,MAAM,sBAAsB,YAAY,KAAK,IAAI,GAC1E;AACF;;;;;;;AAQA,MAAM,gBAAgB,SAAiB,SACrC,IAAI,SAAS,SAAS,WAAW;CAC/B,MAAM,YAAQA,0BAAM,SAAS,MAAM,EAAE,OAAO,UAAU,CAAC;CAEvD,MAAM,GAAG,SAAS,MAAM;CACxB,MAAM,GAAG,UAAU,SAAS,QAAQ,QAAQ,CAAC,CAAC;AAChD,CAAC;;;;;;;AAQH,MAAa,YAAY,OACvB,UAA4B,CAAC,MACX;CAClB,MAAM,IAAI,MAAMC,gCAAY;CAI5B,IAAI,CAAC,QAAQ,QAAQ,CAACC,0DAAsB,GAAG;EAC7C,EAAE,IAAI,MACJ,6FAA6F,YAAY,KAAK,KAAK,EAAE,EACvH;EACA,QAAQ,WAAW;EACnB;CACF;CAEA,MAAM,SAAS,mBAAmB;CAClC,MAAM,YAAY,QAAQ,aAAa,OAAO;CAE9C,MAAM,UAAU,EAAE,QAAQ;CAC1B,QAAQ,MAAM,YAAY,WAAW;CAErC,IAAI;CAEJ,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,SAAS;EAEtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,SAAS,YAAY;EAG7D,SAAS,MAAM,SAAS,KAAK;CAC/B,SAAS,OAAO;EACd,QAAQ,KAAK,kCAAkC;EAC/C,EAAE,IAAI,MACJ,GAAI,MAAgB,QAAQ,qBAC1B,QAAQ,aAAa,UACjB,OAAO,UAAU,UACjB,cAAc,UAAU,QAEhC;EACA,QAAQ,WAAW;EACnB;CACF;CAEA,QAAQ,KAAK,sBAAsB;CAEnC,MAAM,YAAY,UAAMC,8BAAQC,oBAAKC,gBAAO,GAAG,mBAAmB,CAAC;CACnE,MAAM,iBAAaD,gBAAK,WAAW,OAAO,QAAQ;CAElD,IAAI;EACF,UAAME,4BAAU,YAAY,QAAQ,EAAE,MAAM,IAAM,CAAC;EAEnD,MAAM,CAAC,SAAS,QAAQ,OAAO,QAAQ,YAAY,QAAQ,IAAI;EAC/D,MAAM,WAAW,MAAM,aAAa,SAAS,IAAI;EAEjD,IAAI,aAAa,GACf,QAAQ,WAAW;CAEvB,UAAU;EACR,UAAMC,qBAAG,WAAW;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CACtD;AACF"}
@@ -1,21 +1,30 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_loadPrompts = require('./loadPrompts.cjs');
3
+ const require_utils_isInteractiveTerminal = require('./utils/isInteractiveTerminal.cjs');
4
+ const require_utils_parseChoice = require('./utils/parseChoice.cjs');
3
5
  const require_initSkills = require('./initSkills.cjs');
4
6
  const require_init = require('./init.cjs');
5
- let node_path = require("node:path");
6
7
  let _intlayer_engine_cli = require("@intlayer/engine/cli");
7
8
 
8
9
  //#region src/initMCP.ts
9
- const initMCP = async (projectRoot, preselectedPlatform) => {
10
+ /** Validates a `--transport` value, ignoring case. */
11
+ const parseMCPTransport = (value) => require_utils_parseChoice.parseChoice(value, _intlayer_engine_cli.MCP_TRANSPORTS, "--transport");
12
+ /**
13
+ * Configures the Intlayer MCP server for an AI platform. Without a terminal
14
+ * (AI agents, CI), nothing is prompted: the platform defaults to the detected
15
+ * one and the transport to `stdio`.
16
+ */
17
+ const initMCP = async (projectRoot, options = {}) => {
10
18
  const p = await require_loadPrompts.loadPrompts();
11
- const root = require_init.findProjectRoot(projectRoot ? (0, node_path.resolve)(projectRoot) : process.cwd());
19
+ const root = require_init.resolveProjectRoot(projectRoot);
20
+ const isInteractive = require_utils_isInteractiveTerminal.isInteractiveTerminal();
12
21
  p.intro("Initializing Intlayer MCP Server");
13
- const platform = preselectedPlatform ?? await require_initSkills.promptPlatform();
22
+ const platform = isInteractive ? options.platform ?? await require_initSkills.promptPlatform(root) : await require_initSkills.resolvePlatformWithoutPrompt(root, options.platform, "intlayer init mcp");
14
23
  if (!platform) {
15
24
  p.cancel("Operation cancelled. No platform selected.");
16
25
  return;
17
26
  }
18
- const transport = await p.select({
27
+ const transport = options.transport ?? (isInteractive ? await p.select({
19
28
  message: "Which transport method do you want to use?",
20
29
  options: [{
21
30
  value: "stdio",
@@ -26,8 +35,8 @@ const initMCP = async (projectRoot, preselectedPlatform) => {
26
35
  label: "Remote server (SSE)",
27
36
  hint: "Hosted by Intlayer. Documentation only."
28
37
  }]
29
- });
30
- if (p.isCancel(transport) || !transport) {
38
+ }) : "stdio");
39
+ if (p.isCancel(transport)) {
31
40
  p.cancel("Operation cancelled.");
32
41
  return;
33
42
  }
@@ -40,10 +49,12 @@ const initMCP = async (projectRoot, preselectedPlatform) => {
40
49
  } catch (error) {
41
50
  s.stop("Failed to configure MCP Server");
42
51
  p.log.error(error instanceof Error ? error.message : String(error));
52
+ process.exitCode = 1;
43
53
  }
44
54
  p.outro("Intlayer MCP Server initialization complete");
45
55
  };
46
56
 
47
57
  //#endregion
48
58
  exports.initMCP = initMCP;
59
+ exports.parseMCPTransport = parseMCPTransport;
49
60
  //# sourceMappingURL=initMCP.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"initMCP.cjs","names":["loadPrompts","findProjectRoot","resolve","promptPlatform","installMCP"],"sources":["../../src/initMCP.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport {\n installMCP,\n type MCPTransport,\n type Platform,\n} from '@intlayer/engine/cli';\nimport { findProjectRoot } from './init';\nimport { promptPlatform } from './initSkills';\nimport { loadPrompts } from './loadPrompts';\n\nexport const initMCP = async (\n projectRoot?: string,\n preselectedPlatform?: Platform\n) => {\n const p = await loadPrompts();\n\n const root = findProjectRoot(\n projectRoot ? resolve(projectRoot) : process.cwd()\n );\n\n p.intro('Initializing Intlayer MCP Server');\n\n const platform = preselectedPlatform ?? (await promptPlatform());\n\n if (!platform) {\n p.cancel('Operation cancelled. No platform selected.');\n return;\n }\n\n const transport = (await p.select({\n message: 'Which transport method do you want to use?',\n options: [\n {\n value: 'stdio',\n label: 'Local server (stdio)',\n hint: 'Recommended. Integrates all features including CLI tools.',\n },\n {\n value: 'sse',\n label: 'Remote server (SSE)',\n hint: 'Hosted by Intlayer. Documentation only.',\n },\n ],\n })) as MCPTransport;\n\n if (p.isCancel(transport) || !transport) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n const s = p.spinner();\n s.start('Configuring MCP Server...');\n\n try {\n const result = await installMCP(root, platform, transport);\n\n s.stop('MCP Server configured successfully');\n\n p.note(result, 'Success');\n } catch (error) {\n s.stop('Failed to configure MCP Server');\n p.log.error(error instanceof Error ? error.message : String(error));\n }\n\n p.outro('Intlayer MCP Server initialization complete');\n};\n"],"mappings":";;;;;;;;AAUA,MAAa,UAAU,OACrB,aACA,wBACG;CACH,MAAM,IAAI,MAAMA,gCAAY;CAE5B,MAAM,OAAOC,6BACX,kBAAcC,mBAAQ,WAAW,IAAI,QAAQ,IAAI,CACnD;CAEA,EAAE,MAAM,kCAAkC;CAE1C,MAAM,WAAW,uBAAwB,MAAMC,kCAAe;CAE9D,IAAI,CAAC,UAAU;EACb,EAAE,OAAO,4CAA4C;EACrD;CACF;CAEA,MAAM,YAAa,MAAM,EAAE,OAAO;EAChC,SAAS;EACT,SAAS,CACP;GACE,OAAO;GACP,OAAO;GACP,MAAM;EACR,GACA;GACE,OAAO;GACP,OAAO;GACP,MAAM;EACR,CACF;CACF,CAAC;CAED,IAAI,EAAE,SAAS,SAAS,KAAK,CAAC,WAAW;EACvC,EAAE,OAAO,sBAAsB;EAC/B;CACF;CAEA,MAAM,IAAI,EAAE,QAAQ;CACpB,EAAE,MAAM,2BAA2B;CAEnC,IAAI;EACF,MAAM,SAAS,UAAMC,iCAAW,MAAM,UAAU,SAAS;EAEzD,EAAE,KAAK,oCAAoC;EAE3C,EAAE,KAAK,QAAQ,SAAS;CAC1B,SAAS,OAAO;EACd,EAAE,KAAK,gCAAgC;EACvC,EAAE,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CACpE;CAEA,EAAE,MAAM,6CAA6C;AACvD"}
1
+ {"version":3,"file":"initMCP.cjs","names":["parseChoice","MCP_TRANSPORTS","loadPrompts","resolveProjectRoot","isInteractiveTerminal","promptPlatform","resolvePlatformWithoutPrompt","installMCP"],"sources":["../../src/initMCP.ts"],"sourcesContent":["import {\n installMCP,\n MCP_TRANSPORTS,\n type MCPTransport,\n type Platform,\n} from '@intlayer/engine/cli';\nimport { resolveProjectRoot } from './init';\nimport { promptPlatform, resolvePlatformWithoutPrompt } from './initSkills';\nimport { loadPrompts } from './loadPrompts';\nimport { isInteractiveTerminal } from './utils/isInteractiveTerminal';\nimport { parseChoice } from './utils/parseChoice';\n\n/** Options of {@link initMCP}; anything omitted is prompted for. */\nexport type InitMCPOptions = {\n /** AI platform to configure the MCP server for. */\n platform?: Platform;\n /** MCP transport. Defaults to `stdio` without a terminal. */\n transport?: MCPTransport;\n};\n\n/** Validates a `--transport` value, ignoring case. */\nexport const parseMCPTransport = (value: string): MCPTransport =>\n parseChoice(value, MCP_TRANSPORTS, '--transport');\n\n/**\n * Configures the Intlayer MCP server for an AI platform. Without a terminal\n * (AI agents, CI), nothing is prompted: the platform defaults to the detected\n * one and the transport to `stdio`.\n */\nexport const initMCP = async (\n projectRoot?: string,\n options: InitMCPOptions = {}\n) => {\n const p = await loadPrompts();\n\n const root = resolveProjectRoot(projectRoot);\n const isInteractive = isInteractiveTerminal();\n\n p.intro('Initializing Intlayer MCP Server');\n\n const platform = isInteractive\n ? (options.platform ?? (await promptPlatform(root)))\n : await resolvePlatformWithoutPrompt(\n root,\n options.platform,\n 'intlayer init mcp'\n );\n\n if (!platform) {\n p.cancel('Operation cancelled. No platform selected.');\n return;\n }\n\n const transport =\n options.transport ??\n (isInteractive\n ? await p.select<MCPTransport>({\n message: 'Which transport method do you want to use?',\n options: [\n {\n value: 'stdio',\n label: 'Local server (stdio)',\n hint: 'Recommended. Integrates all features including CLI tools.',\n },\n {\n value: 'sse',\n label: 'Remote server (SSE)',\n hint: 'Hosted by Intlayer. Documentation only.',\n },\n ],\n })\n : 'stdio');\n\n if (p.isCancel(transport)) {\n p.cancel('Operation cancelled.');\n return;\n }\n\n const s = p.spinner();\n s.start('Configuring MCP Server...');\n\n try {\n const result = await installMCP(root, platform, transport);\n\n s.stop('MCP Server configured successfully');\n\n p.note(result, 'Success');\n } catch (error) {\n s.stop('Failed to configure MCP Server');\n p.log.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n\n p.outro('Intlayer MCP Server initialization complete');\n};\n"],"mappings":";;;;;;;;;;AAqBA,MAAa,qBAAqB,UAChCA,sCAAY,OAAOC,qCAAgB,aAAa;;;;;;AAOlD,MAAa,UAAU,OACrB,aACA,UAA0B,CAAC,MACxB;CACH,MAAM,IAAI,MAAMC,gCAAY;CAE5B,MAAM,OAAOC,gCAAmB,WAAW;CAC3C,MAAM,gBAAgBC,0DAAsB;CAE5C,EAAE,MAAM,kCAAkC;CAE1C,MAAM,WAAW,gBACZ,QAAQ,YAAa,MAAMC,kCAAe,IAAI,IAC/C,MAAMC,gDACJ,MACA,QAAQ,UACR,mBACF;CAEJ,IAAI,CAAC,UAAU;EACb,EAAE,OAAO,4CAA4C;EACrD;CACF;CAEA,MAAM,YACJ,QAAQ,cACP,gBACG,MAAM,EAAE,OAAqB;EAC3B,SAAS;EACT,SAAS,CACP;GACE,OAAO;GACP,OAAO;GACP,MAAM;EACR,GACA;GACE,OAAO;GACP,OAAO;GACP,MAAM;EACR,CACF;CACF,CAAC,IACD;CAEN,IAAI,EAAE,SAAS,SAAS,GAAG;EACzB,EAAE,OAAO,sBAAsB;EAC/B;CACF;CAEA,MAAM,IAAI,EAAE,QAAQ;CACpB,EAAE,MAAM,2BAA2B;CAEnC,IAAI;EACF,MAAM,SAAS,UAAMC,iCAAW,MAAM,UAAU,SAAS;EAEzD,EAAE,KAAK,oCAAoC;EAE3C,EAAE,KAAK,QAAQ,SAAS;CAC1B,SAAS,OAAO;EACd,EAAE,KAAK,gCAAgC;EACvC,EAAE,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAClE,QAAQ,WAAW;CACrB;CAEA,EAAE,MAAM,6CAA6C;AACvD"}
@@ -1,43 +1,25 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
3
3
  const require_loadPrompts = require('./loadPrompts.cjs');
4
+ const require_utils_isInteractiveTerminal = require('./utils/isInteractiveTerminal.cjs');
5
+ const require_utils_parseChoice = require('./utils/parseChoice.cjs');
4
6
  const require_init = require('./init.cjs');
5
- let node_path = require("node:path");
6
7
  let _intlayer_engine_cli = require("@intlayer/engine/cli");
7
- let node_fs = require("node:fs");
8
8
  let enquirer = require("enquirer");
9
9
  enquirer = require_runtime.__toESM(enquirer);
10
10
 
11
11
  //#region src/initSkills.ts
12
- const PLATFORM_CHECKS = _intlayer_engine_cli.PLATFORMS.filter((platform) => _intlayer_engine_cli.PLATFORMS_METADATA[platform]?.check).map((platform) => ({
13
- check: _intlayer_engine_cli.PLATFORMS_METADATA[platform]?.check ?? (() => false),
14
- platform
15
- }));
16
12
  const PLATFORM_OPTIONS = _intlayer_engine_cli.PLATFORMS.map((platform) => ({
17
13
  value: platform,
18
14
  label: _intlayer_engine_cli.PLATFORMS_METADATA[platform]?.label ?? "",
19
15
  hint: `(${_intlayer_engine_cli.PLATFORMS_METADATA[platform]?.dir})`
20
16
  }));
21
- const getDetectedPlatform = () => PLATFORM_CHECKS.find(({ check }) => check())?.platform;
22
- const getDependencies = (root) => {
23
- try {
24
- const packageJsonPath = (0, node_path.join)(root, "package.json");
25
- if (!(0, node_fs.existsSync)(packageJsonPath)) return {};
26
- const { dependencies = {}, devDependencies = {} } = JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8"));
27
- return {
28
- ...dependencies,
29
- ...devDependencies
30
- };
31
- } catch {
32
- return {};
33
- }
34
- };
35
17
  /**
36
18
  * Asks which AI platform the user is using, preselecting the detected one.
37
19
  * Resolves to `undefined` when the prompt is cancelled.
38
20
  */
39
- const promptPlatform = async () => {
40
- const detectedPlatform = getDetectedPlatform();
21
+ const promptPlatform = async (projectRoot) => {
22
+ const detectedPlatform = (0, _intlayer_engine_cli.detectPlatform)(projectRoot);
41
23
  try {
42
24
  return (await enquirer.default.prompt({
43
25
  type: "autocomplete",
@@ -55,32 +37,50 @@ const promptPlatform = async () => {
55
37
  return;
56
38
  }
57
39
  };
40
+ /** Validates a `--platform` value, ignoring case. */
41
+ const parsePlatform = (value) => require_utils_parseChoice.parseChoice(value, _intlayer_engine_cli.PLATFORMS, "--platform");
42
+ /** Validates the `--skills` values, ignoring case. */
43
+ const parseSkills = (values) => values.flatMap((value) => value.split(",")).filter((value) => value.trim() !== "").map((value) => require_utils_parseChoice.parseChoice(value, _intlayer_engine_cli.SKILLS, "--skills"));
44
+ /**
45
+ * Resolves the platform without prompting: the given one, else the detected
46
+ * one. Logs how to pass it and sets a failing exit code when neither exists.
47
+ */
48
+ const resolvePlatformWithoutPrompt = async (projectRoot, platform, command) => {
49
+ const resolvedPlatform = platform ?? (0, _intlayer_engine_cli.detectPlatform)(projectRoot);
50
+ if (!resolvedPlatform) {
51
+ (await require_loadPrompts.loadPrompts()).log.error(`No AI platform detected. Pass it explicitly: ${command} --platform <platform>\nPlatforms: ${_intlayer_engine_cli.PLATFORMS.join(", ")}`);
52
+ process.exitCode = 1;
53
+ }
54
+ return resolvedPlatform;
55
+ };
58
56
  /**
59
57
  * Installs the Intlayer documentation skills. The skills are picked first, then
60
- * the platform (unless preselected). Resolves to the platform used, so a
61
- * following step (e.g. MCP) can reuse it without asking again.
58
+ * the platform. Without a terminal (AI agents, CI), nothing is prompted: the
59
+ * skills default to the project stack and the platform to the detected one.
60
+ * Resolves to the platform used, so a following step (e.g. MCP) can reuse it
61
+ * without asking again.
62
62
  */
63
- const initSkills = async (projectRoot, preselectedPlatform) => {
63
+ const initSkills = async (projectRoot, options = {}) => {
64
64
  const p = await require_loadPrompts.loadPrompts();
65
- const root = require_init.findProjectRoot(projectRoot ? (0, node_path.resolve)(projectRoot) : process.cwd());
65
+ const root = require_init.resolveProjectRoot(projectRoot);
66
+ const isInteractive = require_utils_isInteractiveTerminal.isInteractiveTerminal();
66
67
  p.intro("Initializing Intlayer skills");
67
- const dependencies = getDependencies(root);
68
- const initialValues = (0, _intlayer_engine_cli.getInitialSkills)(dependencies);
69
- const selectedSkills = await p.multiselect({
68
+ const initialSkills = (0, _intlayer_engine_cli.getInitialSkills)(require_init.getProjectDependencies(root));
69
+ const selectedSkills = options.skills ?? (isInteractive ? await p.multiselect({
70
70
  message: "Select the documentation skills to provide to your AI:",
71
- initialValues,
71
+ initialValues: initialSkills,
72
72
  options: _intlayer_engine_cli.SKILLS.map((skill) => ({
73
73
  value: skill,
74
74
  label: skill,
75
75
  hint: _intlayer_engine_cli.SKILLS_METADATA[skill]
76
76
  })),
77
77
  required: false
78
- });
79
- if (p.isCancel(selectedSkills) || !selectedSkills || selectedSkills.length === 0) {
78
+ }) : initialSkills);
79
+ if (p.isCancel(selectedSkills) || selectedSkills.length === 0) {
80
80
  p.cancel("Operation cancelled. No skills selected.");
81
81
  return;
82
82
  }
83
- const platform = preselectedPlatform ?? await promptPlatform();
83
+ const platform = isInteractive ? options.platform ?? await promptPlatform(root) : await resolvePlatformWithoutPrompt(root, options.platform, "intlayer init skills");
84
84
  if (!platform) {
85
85
  p.cancel("Operation cancelled. No platform selected.");
86
86
  return;
@@ -94,6 +94,7 @@ const initSkills = async (projectRoot, preselectedPlatform) => {
94
94
  } catch (error) {
95
95
  s.stop("Failed to install skills");
96
96
  p.log.error(error instanceof Error ? error.message : String(error));
97
+ process.exitCode = 1;
97
98
  }
98
99
  p.outro("Intlayer skills initialization complete");
99
100
  return platform;
@@ -101,7 +102,9 @@ const initSkills = async (projectRoot, preselectedPlatform) => {
101
102
 
102
103
  //#endregion
103
104
  exports.PLATFORM_OPTIONS = PLATFORM_OPTIONS;
104
- exports.getDetectedPlatform = getDetectedPlatform;
105
105
  exports.initSkills = initSkills;
106
+ exports.parsePlatform = parsePlatform;
107
+ exports.parseSkills = parseSkills;
106
108
  exports.promptPlatform = promptPlatform;
109
+ exports.resolvePlatformWithoutPrompt = resolvePlatformWithoutPrompt;
107
110
  //# sourceMappingURL=initSkills.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"initSkills.cjs","names":["PLATFORMS","PLATFORMS_METADATA","join","existsSync","readFileSync","loadPrompts","findProjectRoot","resolve","getInitialSkills","SKILLS","SKILLS_METADATA","installSkills"],"sources":["../../src/initSkills.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport {\n getInitialSkills,\n installSkills,\n PLATFORMS,\n PLATFORMS_METADATA,\n type Platform,\n SKILLS,\n SKILLS_METADATA,\n} from '@intlayer/engine/cli';\nimport enquirer from 'enquirer';\nimport { findProjectRoot } from './init';\nimport { loadPrompts } from './loadPrompts';\n\nconst PLATFORM_CHECKS: Array<{ check: () => boolean; platform: Platform }> =\n PLATFORMS.filter((platform) => PLATFORMS_METADATA[platform]?.check).map(\n (platform) => ({\n check: PLATFORMS_METADATA[platform]?.check ?? (() => false),\n platform,\n })\n );\n\nexport const PLATFORM_OPTIONS: Array<{\n value: Platform;\n label: string;\n hint: string;\n}> = PLATFORMS.map((platform) => ({\n value: platform,\n label: PLATFORMS_METADATA[platform]?.label ?? '',\n hint: `(${PLATFORMS_METADATA[platform]?.dir})`,\n}));\n\nexport const getDetectedPlatform = (): Platform | undefined =>\n PLATFORM_CHECKS.find(({ check }) => check())?.platform;\n\nconst getDependencies = (root: string): Record<string, string> => {\n try {\n const packageJsonPath = join(root, 'package.json');\n if (!existsSync(packageJsonPath)) return {};\n\n const { dependencies = {}, devDependencies = {} } = JSON.parse(\n readFileSync(packageJsonPath, 'utf-8')\n );\n return { ...dependencies, ...devDependencies };\n } catch {\n return {};\n }\n};\n\n/**\n * Asks which AI platform the user is using, preselecting the detected one.\n * Resolves to `undefined` when the prompt is cancelled.\n */\nexport const promptPlatform = async (): Promise<Platform | undefined> => {\n const detectedPlatform = getDetectedPlatform();\n\n try {\n const response = await enquirer.prompt<{ platform: Platform }>({\n type: 'autocomplete',\n name: 'platform',\n message: 'Which platform are you using? (Type to search)',\n multiple: false,\n initial: detectedPlatform\n ? PLATFORMS.indexOf(detectedPlatform)\n : undefined,\n choices: PLATFORM_OPTIONS.map((option) => ({\n name: option.value,\n message: option.label,\n hint: option.hint,\n })),\n });\n\n return response.platform;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Installs the Intlayer documentation skills. The skills are picked first, then\n * the platform (unless preselected). Resolves to the platform used, so a\n * following step (e.g. MCP) can reuse it without asking again.\n */\nexport const initSkills = async (\n projectRoot?: string,\n preselectedPlatform?: Platform\n): Promise<Platform | undefined> => {\n const p = await loadPrompts();\n\n const root = findProjectRoot(\n projectRoot ? resolve(projectRoot) : process.cwd()\n );\n\n p.intro('Initializing Intlayer skills');\n\n const dependencies = getDependencies(root);\n const initialValues = getInitialSkills(dependencies);\n\n const selectedSkills = await p.multiselect({\n message: 'Select the documentation skills to provide to your AI:',\n initialValues,\n options: SKILLS.map((skill) => ({\n value: skill,\n label: skill,\n hint: SKILLS_METADATA[skill],\n })),\n required: false,\n });\n\n if (\n p.isCancel(selectedSkills) ||\n !selectedSkills ||\n (selectedSkills as string[]).length === 0\n ) {\n p.cancel('Operation cancelled. No skills selected.');\n return;\n }\n\n const platform = preselectedPlatform ?? (await promptPlatform());\n\n if (!platform) {\n p.cancel('Operation cancelled. No platform selected.');\n return;\n }\n\n const s = p.spinner();\n s.start('Installing skills...');\n\n try {\n const result = await installSkills(root, platform, selectedSkills);\n\n s.stop('Skills installed successfully');\n\n p.note(result, 'Success');\n } catch (error) {\n s.stop('Failed to install skills');\n p.log.error(error instanceof Error ? error.message : String(error));\n }\n\n p.outro('Intlayer skills initialization complete');\n\n return platform;\n};\n"],"mappings":";;;;;;;;;;;AAeA,MAAM,kBACJA,+BAAU,QAAQ,aAAaC,wCAAmB,SAAS,EAAE,KAAK,CAAC,CAAC,KACjE,cAAc;CACb,OAAOA,wCAAmB,SAAS,EAAE,gBAAgB;CACrD;AACF,EACF;AAEF,MAAa,mBAIRD,+BAAU,KAAK,cAAc;CAChC,OAAO;CACP,OAAOC,wCAAmB,SAAS,EAAE,SAAS;CAC9C,MAAM,IAAIA,wCAAmB,SAAS,EAAE,IAAI;AAC9C,EAAE;AAEF,MAAa,4BACX,gBAAgB,MAAM,EAAE,YAAY,MAAM,CAAC,CAAC,EAAE;AAEhD,MAAM,mBAAmB,SAAyC;CAChE,IAAI;EACF,MAAM,sBAAkBC,gBAAK,MAAM,cAAc;EACjD,IAAI,KAACC,oBAAW,eAAe,GAAG,OAAO,CAAC;EAE1C,MAAM,EAAE,eAAe,CAAC,GAAG,kBAAkB,CAAC,MAAM,KAAK,UACvDC,sBAAa,iBAAiB,OAAO,CACvC;EACA,OAAO;GAAE,GAAG;GAAc,GAAG;EAAgB;CAC/C,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;;;;AAMA,MAAa,iBAAiB,YAA2C;CACvE,MAAM,mBAAmB,oBAAoB;CAE7C,IAAI;EAgBF,QAAO,MAfgB,iBAAS,OAA+B;GAC7D,MAAM;GACN,MAAM;GACN,SAAS;GACT,UAAU;GACV,SAAS,mBACLJ,+BAAU,QAAQ,gBAAgB,IAClC;GACJ,SAAS,iBAAiB,KAAK,YAAY;IACzC,MAAM,OAAO;IACb,SAAS,OAAO;IAChB,MAAM,OAAO;GACf,EAAE;EACJ,CAAC,EAEc,CAAC;CAClB,QAAQ;EACN;CACF;AACF;;;;;;AAOA,MAAa,aAAa,OACxB,aACA,wBACkC;CAClC,MAAM,IAAI,MAAMK,gCAAY;CAE5B,MAAM,OAAOC,6BACX,kBAAcC,mBAAQ,WAAW,IAAI,QAAQ,IAAI,CACnD;CAEA,EAAE,MAAM,8BAA8B;CAEtC,MAAM,eAAe,gBAAgB,IAAI;CACzC,MAAM,oBAAgBC,uCAAiB,YAAY;CAEnD,MAAM,iBAAiB,MAAM,EAAE,YAAY;EACzC,SAAS;EACT;EACA,SAASC,4BAAO,KAAK,WAAW;GAC9B,OAAO;GACP,OAAO;GACP,MAAMC,qCAAgB;EACxB,EAAE;EACF,UAAU;CACZ,CAAC;CAED,IACE,EAAE,SAAS,cAAc,KACzB,CAAC,kBACA,eAA4B,WAAW,GACxC;EACA,EAAE,OAAO,0CAA0C;EACnD;CACF;CAEA,MAAM,WAAW,uBAAwB,MAAM,eAAe;CAE9D,IAAI,CAAC,UAAU;EACb,EAAE,OAAO,4CAA4C;EACrD;CACF;CAEA,MAAM,IAAI,EAAE,QAAQ;CACpB,EAAE,MAAM,sBAAsB;CAE9B,IAAI;EACF,MAAM,SAAS,UAAMC,oCAAc,MAAM,UAAU,cAAc;EAEjE,EAAE,KAAK,+BAA+B;EAEtC,EAAE,KAAK,QAAQ,SAAS;CAC1B,SAAS,OAAO;EACd,EAAE,KAAK,0BAA0B;EACjC,EAAE,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CACpE;CAEA,EAAE,MAAM,yCAAyC;CAEjD,OAAO;AACT"}
1
+ {"version":3,"file":"initSkills.cjs","names":["PLATFORMS","PLATFORMS_METADATA","detectPlatform","parseChoice","SKILLS","loadPrompts","resolveProjectRoot","isInteractiveTerminal","getInitialSkills","getProjectDependencies","SKILLS_METADATA","installSkills"],"sources":["../../src/initSkills.ts"],"sourcesContent":["import {\n detectPlatform,\n getInitialSkills,\n installSkills,\n PLATFORMS,\n PLATFORMS_METADATA,\n type Platform,\n SKILLS,\n SKILLS_METADATA,\n type Skill,\n} from '@intlayer/engine/cli';\nimport enquirer from 'enquirer';\nimport { getProjectDependencies, resolveProjectRoot } from './init';\nimport { loadPrompts } from './loadPrompts';\nimport { isInteractiveTerminal } from './utils/isInteractiveTerminal';\nimport { parseChoice } from './utils/parseChoice';\n\nexport const PLATFORM_OPTIONS: Array<{\n value: Platform;\n label: string;\n hint: string;\n}> = PLATFORMS.map((platform) => ({\n value: platform,\n label: PLATFORMS_METADATA[platform]?.label ?? '',\n hint: `(${PLATFORMS_METADATA[platform]?.dir})`,\n}));\n\n/**\n * Asks which AI platform the user is using, preselecting the detected one.\n * Resolves to `undefined` when the prompt is cancelled.\n */\nexport const promptPlatform = async (\n projectRoot: string\n): Promise<Platform | undefined> => {\n const detectedPlatform = detectPlatform(projectRoot);\n\n try {\n const response = await enquirer.prompt<{ platform: Platform }>({\n type: 'autocomplete',\n name: 'platform',\n message: 'Which platform are you using? (Type to search)',\n multiple: false,\n initial: detectedPlatform\n ? PLATFORMS.indexOf(detectedPlatform)\n : undefined,\n choices: PLATFORM_OPTIONS.map((option) => ({\n name: option.value,\n message: option.label,\n hint: option.hint,\n })),\n });\n\n return response.platform;\n } catch {\n return undefined;\n }\n};\n\n/** Options of {@link initSkills}; anything omitted is prompted for. */\nexport type InitSkillsOptions = {\n /** AI platform to install the skills for. */\n platform?: Platform;\n /** Skills to install. Defaults to the ones matching the project stack. */\n skills?: Skill[];\n};\n\n/** Validates a `--platform` value, ignoring case. */\nexport const parsePlatform = (value: string): Platform =>\n parseChoice(value, PLATFORMS, '--platform');\n\n/** Validates the `--skills` values, ignoring case. */\nexport const parseSkills = (values: string[]): Skill[] =>\n values\n .flatMap((value) => value.split(','))\n .filter((value) => value.trim() !== '')\n .map((value) => parseChoice(value, SKILLS, '--skills'));\n\n/**\n * Resolves the platform without prompting: the given one, else the detected\n * one. Logs how to pass it and sets a failing exit code when neither exists.\n */\nexport const resolvePlatformWithoutPrompt = async (\n projectRoot: string,\n platform: Platform | undefined,\n command: string\n): Promise<Platform | undefined> => {\n const resolvedPlatform = platform ?? detectPlatform(projectRoot);\n\n if (!resolvedPlatform) {\n const p = await loadPrompts();\n\n p.log.error(\n `No AI platform detected. Pass it explicitly: ${command} --platform <platform>\\nPlatforms: ${PLATFORMS.join(', ')}`\n );\n process.exitCode = 1;\n }\n\n return resolvedPlatform;\n};\n\n/**\n * Installs the Intlayer documentation skills. The skills are picked first, then\n * the platform. Without a terminal (AI agents, CI), nothing is prompted: the\n * skills default to the project stack and the platform to the detected one.\n * Resolves to the platform used, so a following step (e.g. MCP) can reuse it\n * without asking again.\n */\nexport const initSkills = async (\n projectRoot?: string,\n options: InitSkillsOptions = {}\n): Promise<Platform | undefined> => {\n const p = await loadPrompts();\n\n const root = resolveProjectRoot(projectRoot);\n const isInteractive = isInteractiveTerminal();\n\n p.intro('Initializing Intlayer skills');\n\n const initialSkills = getInitialSkills(getProjectDependencies(root));\n\n const selectedSkills =\n options.skills ??\n (isInteractive\n ? await p.multiselect({\n message: 'Select the documentation skills to provide to your AI:',\n initialValues: initialSkills,\n options: SKILLS.map((skill) => ({\n value: skill,\n label: skill,\n hint: SKILLS_METADATA[skill],\n })),\n required: false,\n })\n : initialSkills);\n\n if (p.isCancel(selectedSkills) || selectedSkills.length === 0) {\n p.cancel('Operation cancelled. No skills selected.');\n return;\n }\n\n const platform = isInteractive\n ? (options.platform ?? (await promptPlatform(root)))\n : await resolvePlatformWithoutPrompt(\n root,\n options.platform,\n 'intlayer init skills'\n );\n\n if (!platform) {\n p.cancel('Operation cancelled. No platform selected.');\n return;\n }\n\n const s = p.spinner();\n s.start('Installing skills...');\n\n try {\n const result = await installSkills(root, platform, selectedSkills);\n\n s.stop('Skills installed successfully');\n\n p.note(result, 'Success');\n } catch (error) {\n s.stop('Failed to install skills');\n p.log.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n\n p.outro('Intlayer skills initialization complete');\n\n return platform;\n};\n"],"mappings":";;;;;;;;;;;AAiBA,MAAa,mBAIRA,+BAAU,KAAK,cAAc;CAChC,OAAO;CACP,OAAOC,wCAAmB,SAAS,EAAE,SAAS;CAC9C,MAAM,IAAIA,wCAAmB,SAAS,EAAE,IAAI;AAC9C,EAAE;;;;;AAMF,MAAa,iBAAiB,OAC5B,gBACkC;CAClC,MAAM,uBAAmBC,qCAAe,WAAW;CAEnD,IAAI;EAgBF,QAAO,MAfgB,iBAAS,OAA+B;GAC7D,MAAM;GACN,MAAM;GACN,SAAS;GACT,UAAU;GACV,SAAS,mBACLF,+BAAU,QAAQ,gBAAgB,IAClC;GACJ,SAAS,iBAAiB,KAAK,YAAY;IACzC,MAAM,OAAO;IACb,SAAS,OAAO;IAChB,MAAM,OAAO;GACf,EAAE;EACJ,CAAC,EAEc,CAAC;CAClB,QAAQ;EACN;CACF;AACF;;AAWA,MAAa,iBAAiB,UAC5BG,sCAAY,OAAOH,gCAAW,YAAY;;AAG5C,MAAa,eAAe,WAC1B,OACG,SAAS,UAAU,MAAM,MAAM,GAAG,CAAC,CAAC,CACpC,QAAQ,UAAU,MAAM,KAAK,MAAM,EAAE,CAAC,CACtC,KAAK,UAAUG,sCAAY,OAAOC,6BAAQ,UAAU,CAAC;;;;;AAM1D,MAAa,+BAA+B,OAC1C,aACA,UACA,YACkC;CAClC,MAAM,mBAAmB,gBAAYF,qCAAe,WAAW;CAE/D,IAAI,CAAC,kBAAkB;EAGrB,OAFgBG,gCAAY,EAE3B,CAAC,IAAI,MACJ,gDAAgD,QAAQ,qCAAqCL,+BAAU,KAAK,IAAI,GAClH;EACA,QAAQ,WAAW;CACrB;CAEA,OAAO;AACT;;;;;;;;AASA,MAAa,aAAa,OACxB,aACA,UAA6B,CAAC,MACI;CAClC,MAAM,IAAI,MAAMK,gCAAY;CAE5B,MAAM,OAAOC,gCAAmB,WAAW;CAC3C,MAAM,gBAAgBC,0DAAsB;CAE5C,EAAE,MAAM,8BAA8B;CAEtC,MAAM,oBAAgBC,uCAAiBC,oCAAuB,IAAI,CAAC;CAEnE,MAAM,iBACJ,QAAQ,WACP,gBACG,MAAM,EAAE,YAAY;EAClB,SAAS;EACT,eAAe;EACf,SAASL,4BAAO,KAAK,WAAW;GAC9B,OAAO;GACP,OAAO;GACP,MAAMM,qCAAgB;EACxB,EAAE;EACF,UAAU;CACZ,CAAC,IACD;CAEN,IAAI,EAAE,SAAS,cAAc,KAAK,eAAe,WAAW,GAAG;EAC7D,EAAE,OAAO,0CAA0C;EACnD;CACF;CAEA,MAAM,WAAW,gBACZ,QAAQ,YAAa,MAAM,eAAe,IAAI,IAC/C,MAAM,6BACJ,MACA,QAAQ,UACR,sBACF;CAEJ,IAAI,CAAC,UAAU;EACb,EAAE,OAAO,4CAA4C;EACrD;CACF;CAEA,MAAM,IAAI,EAAE,QAAQ;CACpB,EAAE,MAAM,sBAAsB;CAE9B,IAAI;EACF,MAAM,SAAS,UAAMC,oCAAc,MAAM,UAAU,cAAc;EAEjE,EAAE,KAAK,+BAA+B;EAEtC,EAAE,KAAK,QAAQ,SAAS;CAC1B,SAAS,OAAO;EACd,EAAE,KAAK,0BAA0B;EACjC,EAAE,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAClE,QAAQ,WAAW;CACrB;CAEA,EAAE,MAAM,yCAAyC;CAEjD,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- let node_path = require("node:path");
3
2
  let _intlayer_engine_cli = require("@intlayer/engine/cli");
3
+ let node_path = require("node:path");
4
4
  let _intlayer_config_logger = require("@intlayer/config/logger");
5
5
  let _intlayer_config_node = require("@intlayer/config/node");
6
6
  let _intlayer_engine_utils = require("@intlayer/engine/utils");
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- let node_path = require("node:path");
3
2
  let _intlayer_engine_cli = require("@intlayer/engine/cli");
3
+ let node_path = require("node:path");
4
4
 
5
5
  //#region src/listProjects.ts
6
6
  const listProjectsCommand = async (options) => {
@@ -1 +1 @@
1
- {"version":3,"file":"liveSync.cjs","names":["getAppLogger","buildDictionary","getConfiguration","runParallel","IntlayerEventListener","colorize","ANSIColors","createServer","getDictionaries","getLocalizedContent","getUnmergedDictionaries","packageJson"],"sources":["../../src/liveSync.ts"],"sourcesContent":["import { createServer } from 'node:http';\n// @ts-ignore: @intlayer/backend is not built yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { getLocalizedContent } from '@intlayer/core/plugins';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport { getUnmergedDictionaries } from '@intlayer/dictionaries-entry/unmerged';\nimport { buildDictionary } from '@intlayer/engine/build';\nimport { type ParallelHandle, runParallel } from '@intlayer/engine/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { IntlayerEventListener } from './IntlayerEventListener';\n\ntype LiveSyncOptions = {\n with?: string | string[];\n configOptions?: GetConfigurationOptions;\n};\n\nconst writeDictionary = async (\n dictionary: DictionaryAPI,\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n appLogger(`Writing dictionary ${dictionary.key}`);\n await buildDictionary([dictionary], configuration);\n};\n\nexport const liveSync = async (options?: LiveSyncOptions) => {\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const { liveSyncPort, liveSyncURL } = configuration.editor;\n\n let parallelProcess: ParallelHandle | null = null;\n let eventListener: IntlayerEventListener | null = null;\n let _isHotReloadConnected = false;\n let _connectionStatus = 'disconnected'; // 'connected', 'connecting', 'reconnecting', 'disconnected', 'error'\n\n // Start the parallel process if provided\n if (options?.with) {\n parallelProcess = runParallel(options.with);\n // Handle the promise to avoid unhandled rejection\n parallelProcess.result.catch(() => {\n // Parallel process failed or was terminated\n });\n }\n\n // Initialize the event listener for hot reload if configured\n if (\n configuration.editor.liveSync &&\n configuration.editor.backendURL &&\n configuration.editor.clientId &&\n configuration.editor.clientSecret\n ) {\n eventListener = new IntlayerEventListener(configuration);\n _connectionStatus = 'connecting';\n\n // Set up connection callbacks\n eventListener.onConnectionOpen = () => {\n _connectionStatus = 'connected';\n _isHotReloadConnected = true;\n appLogger('Live sync connection established');\n };\n\n eventListener.onConnectionError = (error) => {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n const errorEvent = error as any;\n appLogger(\n `Live sync connection error: ${errorEvent.message ?? 'Unknown error'}`,\n {\n level: 'warn',\n }\n );\n\n // If this is a \"terminated: other side closed\" error, it's likely a server restart\n if (\n errorEvent.message?.includes('terminated') ||\n errorEvent.message?.includes('closed')\n ) {\n appLogger(\n 'Server connection was terminated, automatic reconnection will be attempted...',\n {\n level: 'info',\n }\n );\n _connectionStatus = 'reconnecting';\n }\n };\n\n // Set up dictionary change callbacks\n eventListener.onDictionaryAdded = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryChange = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryDeleted = (dictionary) =>\n writeDictionary(dictionary, configuration);\n\n try {\n await eventListener.initialize();\n } catch (error) {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n appLogger('Failed to initialize IntlayerEventListener:', {\n level: 'error',\n });\n appLogger(\n `Error: ${error instanceof Error ? error.message : String(error)}`,\n {\n level: 'error',\n }\n );\n }\n } else if (!configuration.editor.liveSync) {\n appLogger(\n `Hot reload is ${colorize('disabled', ANSIColors.RED)}. Please enable it in the configuration (${colorize('editor.liveSync', ANSIColors.BLUE)}).`\n );\n } else if (\n !configuration.editor.clientId ||\n !configuration.editor.clientSecret\n ) {\n appLogger(\n 'Missing client credentials for hot reload. Please configure clientId and clientSecret'\n );\n }\n\n const server = createServer(async (req, res) => {\n // Handle CORS preflight requests\n if (req.method === 'OPTIONS') {\n res.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n\n res.end();\n return;\n }\n\n if (req.url?.startsWith('/dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const dictionaries = getDictionaries(configuration);\n\n const prefix = '/dictionaries/';\n if (req.url.startsWith(prefix)) {\n const [key, locale] = decodeURIComponent(req.url)\n .slice(prefix.length)\n .split('/');\n\n if (!key) {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n const dictionary = dictionaries[key] ?? null;\n\n if (!dictionary) {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n if (locale) {\n // @ts-ignore Type instantiation is excessively deep and possibly infinite\n const sourceLocaleContent = getLocalizedContent(\n dictionary.content,\n locale,\n {\n dictionaryKey: key,\n keyPath: [],\n }\n );\n\n res.end(JSON.stringify(sourceLocaleContent));\n return;\n }\n\n res.end(JSON.stringify(dictionary));\n return;\n }\n\n res.end(JSON.stringify(dictionaries));\n return;\n }\n\n if (req.url?.startsWith('/unmerged_dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const unmergedDictionaries = getUnmergedDictionaries(configuration);\n\n const prefix = '/unmerged_dictionaries/';\n if (req.url.startsWith(prefix)) {\n const key = decodeURIComponent(req.url.slice(prefix.length));\n const one = unmergedDictionaries[key] ?? null;\n\n res.end(JSON.stringify(one));\n return;\n }\n\n res.end(JSON.stringify(unmergedDictionaries));\n return;\n }\n\n if (req.url === '/configuration') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n res.end(JSON.stringify(configuration));\n return;\n }\n\n if (req.url === '/health') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n });\n res.end(JSON.stringify({ status: 'ok' }));\n return;\n }\n\n res.end('Not found');\n return;\n });\n\n const getLiveSyncParam = () => {\n if (!configuration.editor.liveSync) return '\\x1b[31m✗ Disabled\\x1b[0m';\n\n return '\\x1b[32m✓ Enabled\\x1b[0m';\n };\n server.listen(liveSyncPort, () => {\n console.log(`\n \\x1b[1;90mINTLAYER v${packageJson.version}\\x1b[0m\n \n Live server running at: \\x1b[90m${liveSyncURL}\\x1b[0m\n - Backend URL: \\x1b[90m${configuration.editor.backendURL ?? '-'}\\x1b[0m\n - Live sync: ${getLiveSyncParam()}\n - Parallel process: ${options?.with ? `\\x1b[90m${Array.isArray(options.with) ? options.with.join(' ') : options.with}\\x1b[0m` : '-'}\n - Access key: ${configuration.editor.clientId ?? '-'}\n `);\n });\n\n // Cleanup function to terminate child process and event listener when the main process exits\n const cleanup = () => {\n // Clean up event listener\n if (eventListener) {\n appLogger('Closing SSE connection...');\n eventListener.cleanup();\n }\n\n if (parallelProcess) {\n parallelProcess.kill();\n }\n\n server.close(() => {\n appLogger('Live sync server stopped');\n process.exit(0);\n });\n };\n\n // Handle process termination signals\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n process.on('exit', cleanup);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"liveSync.cjs","names":["getAppLogger","buildDictionary","getConfiguration","runParallel","IntlayerEventListener","colorize","ANSIColors","createServer","getDictionaries","getLocalizedContent","getUnmergedDictionaries","packageJson"],"sources":["../../src/liveSync.ts"],"sourcesContent":["import { createServer } from 'node:http';\nimport type { DictionaryAPI } from '@intlayer/api';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { getLocalizedContent } from '@intlayer/core/plugins';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport { getUnmergedDictionaries } from '@intlayer/dictionaries-entry/unmerged';\nimport { buildDictionary } from '@intlayer/engine/build';\nimport { type ParallelHandle, runParallel } from '@intlayer/engine/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { IntlayerEventListener } from './IntlayerEventListener';\n\ntype LiveSyncOptions = {\n with?: string | string[];\n configOptions?: GetConfigurationOptions;\n};\n\nconst writeDictionary = async (\n dictionary: DictionaryAPI,\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n appLogger(`Writing dictionary ${dictionary.key}`);\n await buildDictionary([dictionary], configuration);\n};\n\nexport const liveSync = async (options?: LiveSyncOptions) => {\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const { liveSyncPort, liveSyncURL } = configuration.editor;\n\n let parallelProcess: ParallelHandle | null = null;\n let eventListener: IntlayerEventListener | null = null;\n let _isHotReloadConnected = false;\n let _connectionStatus = 'disconnected'; // 'connected', 'connecting', 'reconnecting', 'disconnected', 'error'\n\n // Start the parallel process if provided\n if (options?.with) {\n parallelProcess = runParallel(options.with);\n // Handle the promise to avoid unhandled rejection\n parallelProcess.result.catch(() => {\n // Parallel process failed or was terminated\n });\n }\n\n // Initialize the event listener for hot reload if configured\n if (\n configuration.editor.liveSync &&\n configuration.editor.backendURL &&\n configuration.editor.clientId &&\n configuration.editor.clientSecret\n ) {\n eventListener = new IntlayerEventListener(configuration);\n _connectionStatus = 'connecting';\n\n // Set up connection callbacks\n eventListener.onConnectionOpen = () => {\n _connectionStatus = 'connected';\n _isHotReloadConnected = true;\n appLogger('Live sync connection established');\n };\n\n eventListener.onConnectionError = (error) => {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n const errorEvent = error as any;\n appLogger(\n `Live sync connection error: ${errorEvent.message ?? 'Unknown error'}`,\n {\n level: 'warn',\n }\n );\n\n // If this is a \"terminated: other side closed\" error, it's likely a server restart\n if (\n errorEvent.message?.includes('terminated') ||\n errorEvent.message?.includes('closed')\n ) {\n appLogger(\n 'Server connection was terminated, automatic reconnection will be attempted...',\n {\n level: 'info',\n }\n );\n _connectionStatus = 'reconnecting';\n }\n };\n\n // Set up dictionary change callbacks\n eventListener.onDictionaryAdded = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryChange = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryDeleted = (dictionary) =>\n writeDictionary(dictionary, configuration);\n\n try {\n await eventListener.initialize();\n } catch (error) {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n appLogger('Failed to initialize IntlayerEventListener:', {\n level: 'error',\n });\n appLogger(\n `Error: ${error instanceof Error ? error.message : String(error)}`,\n {\n level: 'error',\n }\n );\n }\n } else if (!configuration.editor.liveSync) {\n appLogger(\n `Hot reload is ${colorize('disabled', ANSIColors.RED)}. Please enable it in the configuration (${colorize('editor.liveSync', ANSIColors.BLUE)}).`\n );\n } else if (\n !configuration.editor.clientId ||\n !configuration.editor.clientSecret\n ) {\n appLogger(\n 'Missing client credentials for hot reload. Please configure clientId and clientSecret'\n );\n }\n\n const server = createServer(async (req, res) => {\n // Handle CORS preflight requests\n if (req.method === 'OPTIONS') {\n res.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n\n res.end();\n return;\n }\n\n if (req.url?.startsWith('/dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const dictionaries = getDictionaries(configuration);\n\n const prefix = '/dictionaries/';\n if (req.url.startsWith(prefix)) {\n const [key, locale] = decodeURIComponent(req.url)\n .slice(prefix.length)\n .split('/');\n\n if (!key) {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n const dictionary = dictionaries[key] ?? null;\n\n if (!dictionary) {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n if (locale) {\n // @ts-ignore Type instantiation is excessively deep and possibly infinite\n const sourceLocaleContent = getLocalizedContent(\n dictionary.content,\n locale,\n {\n dictionaryKey: key,\n keyPath: [],\n }\n );\n\n res.end(JSON.stringify(sourceLocaleContent));\n return;\n }\n\n res.end(JSON.stringify(dictionary));\n return;\n }\n\n res.end(JSON.stringify(dictionaries));\n return;\n }\n\n if (req.url?.startsWith('/unmerged_dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const unmergedDictionaries = getUnmergedDictionaries(configuration);\n\n const prefix = '/unmerged_dictionaries/';\n if (req.url.startsWith(prefix)) {\n const key = decodeURIComponent(req.url.slice(prefix.length));\n const one = unmergedDictionaries[key] ?? null;\n\n res.end(JSON.stringify(one));\n return;\n }\n\n res.end(JSON.stringify(unmergedDictionaries));\n return;\n }\n\n if (req.url === '/configuration') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n res.end(JSON.stringify(configuration));\n return;\n }\n\n if (req.url === '/health') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n });\n res.end(JSON.stringify({ status: 'ok' }));\n return;\n }\n\n res.end('Not found');\n return;\n });\n\n const getLiveSyncParam = () => {\n if (!configuration.editor.liveSync) return '\\x1b[31m✗ Disabled\\x1b[0m';\n\n return '\\x1b[32m✓ Enabled\\x1b[0m';\n };\n server.listen(liveSyncPort, () => {\n console.log(`\n \\x1b[1;90mINTLAYER v${packageJson.version}\\x1b[0m\n \n Live server running at: \\x1b[90m${liveSyncURL}\\x1b[0m\n - Backend URL: \\x1b[90m${configuration.editor.backendURL ?? '-'}\\x1b[0m\n - Live sync: ${getLiveSyncParam()}\n - Parallel process: ${options?.with ? `\\x1b[90m${Array.isArray(options.with) ? options.with.join(' ') : options.with}\\x1b[0m` : '-'}\n - Access key: ${configuration.editor.clientId ?? '-'}\n `);\n });\n\n // Cleanup function to terminate child process and event listener when the main process exits\n const cleanup = () => {\n // Clean up event listener\n if (eventListener) {\n appLogger('Closing SSE connection...');\n eventListener.cleanup();\n }\n\n if (parallelProcess) {\n parallelProcess.kill();\n }\n\n server.close(() => {\n appLogger('Live sync server stopped');\n process.exit(0);\n });\n };\n\n // Handle process termination signals\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n process.on('exit', cleanup);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAsBA,MAAM,kBAAkB,OACtB,YACA,kBACG;CAEH,IADkBA,sCAAa,aACvB,CAAC,CAAC,sBAAsB,WAAW,KAAK;CAChD,UAAMC,wCAAgB,CAAC,UAAU,GAAG,aAAa;AACnD;AAEA,MAAa,WAAW,OAAO,YAA8B;CAC3D,MAAM,oBAAgBC,wCAAiB,SAAS,aAAa;CAC7D,MAAM,gBAAYF,sCAAa,aAAa;CAE5C,MAAM,EAAE,cAAc,gBAAgB,cAAc;CAEpD,IAAI,kBAAyC;CAC7C,IAAI,gBAA8C;CAKlD,IAAI,SAAS,MAAM;EACjB,sBAAkBG,oCAAY,QAAQ,IAAI;EAE1C,gBAAgB,OAAO,YAAY,CAEnC,CAAC;CACH;CAGA,IACE,cAAc,OAAO,YACrB,cAAc,OAAO,cACrB,cAAc,OAAO,YACrB,cAAc,OAAO,cACrB;EACA,gBAAgB,IAAIC,oDAAsB,aAAa;EAIvD,cAAc,yBAAyB;GAGrC,UAAU,kCAAkC;EAC9C;EAEA,cAAc,qBAAqB,UAAU;GAG3C,MAAM,aAAa;GACnB,UACE,+BAA+B,WAAW,WAAW,mBACrD,EACE,OAAO,OACT,CACF;GAGA,IACE,WAAW,SAAS,SAAS,YAAY,KACzC,WAAW,SAAS,SAAS,QAAQ,GAErC,UACE,iFACA,EACE,OAAO,OACT,CACF;EAGJ;EAGA,cAAc,qBAAqB,eACjC,gBAAgB,YAAY,aAAa;EAC3C,cAAc,sBAAsB,eAClC,gBAAgB,YAAY,aAAa;EAC3C,cAAc,uBAAuB,eACnC,gBAAgB,YAAY,aAAa;EAE3C,IAAI;GACF,MAAM,cAAc,WAAW;EACjC,SAAS,OAAO;GAGd,UAAU,+CAA+C,EACvD,OAAO,QACT,CAAC;GACD,UACE,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KAC/D,EACE,OAAO,QACT,CACF;EACF;CACF,OAAO,IAAI,CAAC,cAAc,OAAO,UAC/B,UACE,qBAAiBC,kCAAS,YAAYC,wBAAW,GAAG,EAAE,+CAA2CD,kCAAS,mBAAmBC,wBAAW,IAAI,EAAE,GAChJ;MACK,IACL,CAAC,cAAc,OAAO,YACtB,CAAC,cAAc,OAAO,cAEtB,UACE,uFACF;CAGF,MAAM,aAASC,wBAAa,OAAO,KAAK,QAAQ;EAE9C,IAAI,IAAI,WAAW,WAAW;GAC5B,IAAI,UAAU,KAAK;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;GAClC,CAAC;GAED,IAAI,IAAI;GACR;EACF;EAEA,IAAI,IAAI,KAAK,WAAW,eAAe,GAAG;GACxC,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;GAClC,CAAC;GACD,MAAM,mBAAeC,8CAAgB,aAAa;GAGlD,IAAI,IAAI,IAAI,WAAW,gBAAM,GAAG;IAC9B,MAAM,CAAC,KAAK,UAAU,mBAAmB,IAAI,GAAG,CAAC,CAC9C,MAAM,EAAa,CAAC,CACpB,MAAM,GAAG;IAEZ,IAAI,CAAC,KAAK;KACR,IAAI,UAAU,GAAG;KACjB,IAAI,IAAI,WAAW;KACnB;IACF;IAEA,MAAM,aAAa,aAAa,QAAQ;IAExC,IAAI,CAAC,YAAY;KACf,IAAI,UAAU,GAAG;KACjB,IAAI,IAAI,WAAW;KACnB;IACF;IAEA,IAAI,QAAQ;KAEV,MAAM,0BAAsBC,4CAC1B,WAAW,SACX,QACA;MACE,eAAe;MACf,SAAS,CAAC;KACZ,CACF;KAEA,IAAI,IAAI,KAAK,UAAU,mBAAmB,CAAC;KAC3C;IACF;IAEA,IAAI,IAAI,KAAK,UAAU,UAAU,CAAC;IAClC;GACF;GAEA,IAAI,IAAI,KAAK,UAAU,YAAY,CAAC;GACpC;EACF;EAEA,IAAI,IAAI,KAAK,WAAW,wBAAwB,GAAG;GACjD,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;GAClC,CAAC;GACD,MAAM,2BAAuBC,+DAAwB,aAAa;GAGlE,IAAI,IAAI,IAAI,WAAW,yBAAM,GAAG;IAE9B,MAAM,MAAM,qBADA,mBAAmB,IAAI,IAAI,MAAM,EAAa,CACvB,MAAM;IAEzC,IAAI,IAAI,KAAK,UAAU,GAAG,CAAC;IAC3B;GACF;GAEA,IAAI,IAAI,KAAK,UAAU,oBAAoB,CAAC;GAC5C;EACF;EAEA,IAAI,IAAI,QAAQ,kBAAkB;GAChC,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;GAClC,CAAC;GACD,IAAI,IAAI,KAAK,UAAU,aAAa,CAAC;GACrC;EACF;EAEA,IAAI,IAAI,QAAQ,WAAW;GACzB,IAAI,UAAU,KAAK,EACjB,gBAAgB,kCAClB,CAAC;GACD,IAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,KAAK,CAAC,CAAC;GACxC;EACF;EAEA,IAAI,IAAI,WAAW;CAErB,CAAC;CAED,MAAM,yBAAyB;EAC7B,IAAI,CAAC,cAAc,OAAO,UAAU,OAAO;EAE3C,OAAO;CACT;CACA,OAAO,OAAO,oBAAoB;EAChC,QAAQ,IAAI;4BACYC,sCAAY,QAAQ;;iDAEC,YAAY;iDACZ,cAAc,OAAO,cAAc,IAAI;yCAC/C,iBAAiB,EAAE;yCACnB,SAAS,OAAO,WAAW,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,KAAK,KAAK,GAAG,IAAI,QAAQ,KAAK,WAAW,IAAI;yCAC9G,cAAc,OAAO,YAAY,IAAI;OACvE;CACL,CAAC;CAGD,MAAM,gBAAgB;EAEpB,IAAI,eAAe;GACjB,UAAU,2BAA2B;GACrC,cAAc,QAAQ;EACxB;EAEA,IAAI,iBACF,gBAAgB,KAAK;EAGvB,OAAO,YAAY;GACjB,UAAU,0BAA0B;GACpC,QAAQ,KAAK,CAAC;EAChB,CAAC;CACH;CAGA,QAAQ,GAAG,UAAU,OAAO;CAC5B,QAAQ,GAAG,WAAW,OAAO;CAC7B,QAAQ,GAAG,QAAQ,OAAO;AAC5B"}
package/dist/cjs/pull.cjs CHANGED
@@ -3,9 +3,9 @@ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
3
3
  const require_utils_checkAccess = require('./utils/checkAccess.cjs');
4
4
  const require_push_pullLog = require('./push/pullLog.cjs');
5
5
  const require_utils_selectCmsEnvironment = require('./utils/selectCmsEnvironment.cjs');
6
- let node_path = require("node:path");
7
6
  let _intlayer_engine_cli = require("@intlayer/engine/cli");
8
7
  let node_fs = require("node:fs");
8
+ let node_path = require("node:path");
9
9
  let _intlayer_config_colors = require("@intlayer/config/colors");
10
10
  _intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
11
11
  let _intlayer_config_logger = require("@intlayer/config/logger");