@intlayer/engine 9.0.0-canary.15 → 9.0.0-canary.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,100 @@
1
+ import { getGitRootDir, listProjects } from "../../listProjects.mjs";
2
+ import { detectPackageManager } from "./packageManager.mjs";
3
+ import { join, relative, resolve, sep } from "node:path";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+
1
6
  //#region src/init/utils/githubActions.ts
2
7
  /**
8
+ * Returns true when the repository root hosts a workspace manifest
9
+ * (a `package.json` `workspaces` field or a `pnpm-workspace.yaml`), meaning a
10
+ * single install at the root covers every package of the monorepo.
11
+ */
12
+ const hasWorkspaceManifest = (repositoryRootDir) => {
13
+ if (existsSync(join(repositoryRootDir, "pnpm-workspace.yaml"))) return true;
14
+ try {
15
+ const packageJsonPath = join(repositoryRootDir, "package.json");
16
+ if (!existsSync(packageJsonPath)) return false;
17
+ const { workspaces } = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
18
+ return Boolean(workspaces);
19
+ } catch {
20
+ return false;
21
+ }
22
+ };
23
+ /**
24
+ * Resolves where the CI workflows must be written and how their commands must
25
+ * be generated, based on the repository layout around `rootDir` (the Intlayer
26
+ * project being initialized):
27
+ *
28
+ * - Project at the repository root: workflows are written in place. When the
29
+ * repository is a monorepo (workspace manifest, or several Intlayer projects
30
+ * discovered by `listProjects`), the commands go through `intlayer ci` so
31
+ * every project is covered.
32
+ * - Project nested in a repository whose root has a `package.json`
33
+ * (workspace-managed monorepo): workflows are written at the git root —
34
+ * GitHub ignores `.github/workflows` in subdirectories — dependencies are
35
+ * installed at the root with the root's package manager, and the commands go
36
+ * through `intlayer ci` to iterate every Intlayer project.
37
+ * - Project nested in a repository without a root `package.json`: workflows
38
+ * are written at the git root but run inside the project directory
39
+ * (`working-directory`), keeping the project's own package manager.
40
+ */
41
+ const resolveGithubWorkflowsContext = async (rootDir, projectPackageManager) => {
42
+ const projectRootDir = resolve(rootDir);
43
+ let repositoryRootDir = projectRootDir;
44
+ try {
45
+ const gitRootDir = await getGitRootDir(projectRootDir);
46
+ if (gitRootDir) repositoryRootDir = resolve(gitRootDir);
47
+ } catch {}
48
+ let repositoryProjectCount = 0;
49
+ try {
50
+ const { projectsPath } = await listProjects({ baseDir: repositoryRootDir });
51
+ repositoryProjectCount = projectsPath.length;
52
+ } catch {
53
+ repositoryProjectCount = 0;
54
+ }
55
+ const isNestedProject = repositoryRootDir !== projectRootDir;
56
+ const isWorkspaceRepository = hasWorkspaceManifest(repositoryRootDir);
57
+ const hasRootPackageJson = existsSync(join(repositoryRootDir, "package.json"));
58
+ if (!isNestedProject) return {
59
+ workflowsRootDir: projectRootDir,
60
+ packageManager: projectPackageManager,
61
+ options: { useCiCommand: isWorkspaceRepository || repositoryProjectCount > 1 }
62
+ };
63
+ if (hasRootPackageJson) return {
64
+ workflowsRootDir: repositoryRootDir,
65
+ packageManager: detectPackageManager(repositoryRootDir),
66
+ options: { useCiCommand: true }
67
+ };
68
+ return {
69
+ workflowsRootDir: repositoryRootDir,
70
+ packageManager: projectPackageManager,
71
+ options: { workingDirectory: relative(repositoryRootDir, projectRootDir).split(sep).join("/") }
72
+ };
73
+ };
74
+ /** Dependency lock file of each package manager, used for cache invalidation. */
75
+ const LOCK_FILE_BY_PACKAGE_MANAGER = {
76
+ bun: "bun.lock",
77
+ pnpm: "pnpm-lock.yaml",
78
+ yarn: "yarn.lock",
79
+ npm: "package-lock.json"
80
+ };
81
+ /**
3
82
  * Returns the package-manager-specific steps and commands used to build the
4
83
  * GitHub Actions workflows. Each package manager needs a slightly different
5
84
  * setup action and a different way to run the local `intlayer` binary.
85
+ *
86
+ * `workingDirectory` is the repository-relative directory holding the lock
87
+ * file when the project is nested: `actions/setup-node` looks for the lock
88
+ * file at the repository root by default and fails the cache setup otherwise.
6
89
  */
7
- const getPackageManagerCIConfig = (packageManager) => {
8
- const setupNodeStep = (cache) => ` - name: 🟢 Setup Node.js
90
+ const getPackageManagerCIConfig = (packageManager, workingDirectory) => {
91
+ const setupNodeStep = (cache) => {
92
+ const cacheDependencyPath = cache && workingDirectory ? `\n cache-dependency-path: ${workingDirectory}/${LOCK_FILE_BY_PACKAGE_MANAGER[cache]}` : "";
93
+ return ` - name: 🟢 Setup Node.js
9
94
  uses: actions/setup-node@v4
10
95
  with:
11
- node-version: 20${cache ? `\n cache: ${cache}` : ""}`;
96
+ node-version: 20${cache ? `\n cache: ${cache}` : ""}${cacheDependencyPath}`;
97
+ };
12
98
  switch (packageManager) {
13
99
  case "bun": return {
14
100
  setupSteps: ` - name: 🥟 Setup Bun
@@ -36,6 +122,27 @@ ${setupNodeStep("pnpm")}`,
36
122
  }
37
123
  };
38
124
  /**
125
+ * Renders the `defaults.run.working-directory` block for jobs that must run
126
+ * inside a nested project directory. Empty when the commands run at the
127
+ * repository root.
128
+ */
129
+ const getWorkingDirectoryBlock = (workingDirectory) => workingDirectory ? `
130
+ defaults:
131
+ run:
132
+ working-directory: ${workingDirectory}` : "";
133
+ /**
134
+ * Renders the env comment + optional wiring for per-project credentials in
135
+ * monorepo (`intlayer ci`) mode. The `ci` command matches each entry of the
136
+ * `INTLAYER_PROJECT_CREDENTIALS` JSON map to a discovered project path and
137
+ * injects its access keys before running the command in that project.
138
+ */
139
+ const getMonorepoCredentialsBlock = (useCiCommand) => useCiCommand ? `
140
+ #
141
+ # Monorepo — per-project CMS credentials, as a JSON map of project path
142
+ # (relative to the repository root) to access keys, e.g.
143
+ # {"apps/web":{"clientId":"...","clientSecret":"..."}}:
144
+ # INTLAYER_PROJECT_CREDENTIALS: \${{ secrets.INTLAYER_PROJECT_CREDENTIALS }}` : "";
145
+ /**
39
146
  * Builds the `intlayer fill` workflow. Runs on pull requests, regenerates the
40
147
  * missing translations for the changed dictionaries (`--git-diff`) using AI,
41
148
  * then commits the result back to the PR branch.
@@ -44,8 +151,9 @@ ${setupNodeStep("pnpm")}`,
44
151
  * - a provider API key (`AI_API_KEY` secret), forwarded via CLI flags, or
45
152
  * - Intlayer CMS access keys (`INTLAYER_CLIENT_ID` / `INTLAYER_CLIENT_SECRET`).
46
153
  */
47
- const generateFillWorkflow = (packageManager) => {
48
- const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(packageManager);
154
+ const generateFillWorkflow = (packageManager, options) => {
155
+ const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(packageManager, options.workingDirectory);
156
+ const intlayerCommand = options.useCiCommand ? `${execCommand} ci` : execCommand;
49
157
  return `name: Intlayer Fill
50
158
  # Auto-fill missing translations on every pull request.
51
159
  on:
@@ -63,7 +171,7 @@ concurrency:
63
171
 
64
172
  jobs:
65
173
  fill:
66
- runs-on: ubuntu-latest
174
+ runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}
67
175
  env:
68
176
  # AI access is required to generate translations.
69
177
  # Add the secret in: Settings → Secrets and variables → Actions.
@@ -76,7 +184,7 @@ jobs:
76
184
  # Option 2 — Use Intlayer CMS access keys instead of your own AI key.
77
185
  # Wire them in your intlayer.config and uncomment the lines below:
78
186
  # INTLAYER_CLIENT_ID: \${{ secrets.INTLAYER_CLIENT_ID }}
79
- # INTLAYER_CLIENT_SECRET: \${{ secrets.INTLAYER_CLIENT_SECRET }}
187
+ # INTLAYER_CLIENT_SECRET: \${{ secrets.INTLAYER_CLIENT_SECRET }}${getMonorepoCredentialsBlock(options.useCiCommand)}
80
188
  steps:
81
189
  - name: ⬇️ Checkout repository
82
190
  uses: actions/checkout@v4
@@ -87,12 +195,12 @@ ${setupSteps}
87
195
  - name: 📦 Install dependencies
88
196
  run: ${installCommand}
89
197
  - name: ⚙️ Build dictionaries
90
- run: ${execCommand} build
198
+ run: ${intlayerCommand} build
91
199
  - name: 🤖 Fill missing translations
92
200
  # Skip when no AI credentials are configured, so the workflow stays green
93
201
  # until an \`AI_API_KEY\` (or Intlayer CMS access keys) secret is added.
94
202
  if: \${{ env.AI_API_KEY != '' || env.INTLAYER_CLIENT_ID != '' }}
95
- run: ${execCommand} fill --git-diff --mode complete --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY
203
+ run: ${intlayerCommand} fill --git-diff --mode complete --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY
96
204
  - name: 📤 Commit and push changes
97
205
  run: |
98
206
  git config --local user.email "github-actions[bot]@users.noreply.github.com"
@@ -110,8 +218,9 @@ ${setupSteps}
110
218
  * Builds the `intlayer test` workflow. Runs on pull requests and fails the
111
219
  * check when required locales are missing translations. No AI access needed.
112
220
  */
113
- const generateTestWorkflow = (packageManager) => {
114
- const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(packageManager);
221
+ const generateTestWorkflow = (packageManager, options) => {
222
+ const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(packageManager, options.workingDirectory);
223
+ const intlayerCommand = options.useCiCommand ? `${execCommand} ci` : execCommand;
115
224
  return `name: Intlayer Test
116
225
  # Fail the pull request when required locales are missing translations.
117
226
  on:
@@ -125,7 +234,7 @@ concurrency:
125
234
 
126
235
  jobs:
127
236
  test:
128
- runs-on: ubuntu-latest
237
+ runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}
129
238
  steps:
130
239
  - name: ⬇️ Checkout repository
131
240
  uses: actions/checkout@v4
@@ -133,9 +242,9 @@ ${setupSteps}
133
242
  - name: 📦 Install dependencies
134
243
  run: ${installCommand}
135
244
  - name: ⚙️ Build dictionaries
136
- run: ${execCommand} build
245
+ run: ${intlayerCommand} build
137
246
  - name: 🧪 Test for missing translations
138
- run: ${execCommand} test
247
+ run: ${intlayerCommand} test
139
248
  `;
140
249
  };
141
250
  /** Workflow file path constants, relative to the project root. */
@@ -143,16 +252,18 @@ const GITHUB_FILL_WORKFLOW_PATH = ".github/workflows/intlayer-fill.yml";
143
252
  const GITHUB_TEST_WORKFLOW_PATH = ".github/workflows/intlayer-test.yml";
144
253
  /**
145
254
  * Returns the two Intlayer GitHub Actions workflows (`fill` and `test`),
146
- * generated with commands matching the detected package manager.
255
+ * generated with commands matching the detected package manager and the
256
+ * repository layout (see {@link GithubWorkflowsOptions} for the monorepo and
257
+ * nested-project variants).
147
258
  */
148
- const getGithubWorkflows = (packageManager) => [{
259
+ const getGithubWorkflows = (packageManager, options = {}) => [{
149
260
  filePath: GITHUB_FILL_WORKFLOW_PATH,
150
- content: generateFillWorkflow(packageManager)
261
+ content: generateFillWorkflow(packageManager, options)
151
262
  }, {
152
263
  filePath: GITHUB_TEST_WORKFLOW_PATH,
153
- content: generateTestWorkflow(packageManager)
264
+ content: generateTestWorkflow(packageManager, options)
154
265
  }];
155
266
 
156
267
  //#endregion
157
- export { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, getGithubWorkflows };
268
+ export { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, getGithubWorkflows, resolveGithubWorkflowsContext };
158
269
  //# sourceMappingURL=githubActions.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"githubActions.mjs","names":[],"sources":["../../../../src/init/utils/githubActions.ts"],"sourcesContent":["import type { PackageManager } from './packageManager';\n\n/** A GitHub Actions workflow file to be written to the project. */\nexport type GithubWorkflowFile = {\n /** Path relative to the project root, e.g. `.github/workflows/intlayer-fill.yml`. */\n filePath: string;\n /** Full YAML content of the workflow file. */\n content: string;\n};\n\n/**\n * Package-manager-specific snippets used to assemble the CI workflows.\n * - `setupSteps`: YAML steps (already indented for the `steps:` list) that\n * install the package manager and Node.js, including dependency caching.\n * - `installCommand`: command that installs the project dependencies.\n * - `execCommand`: prefix used to run the locally installed `intlayer` binary.\n */\ntype PackageManagerCIConfig = {\n setupSteps: string;\n installCommand: string;\n execCommand: string;\n};\n\n/**\n * Returns the package-manager-specific steps and commands used to build the\n * GitHub Actions workflows. Each package manager needs a slightly different\n * setup action and a different way to run the local `intlayer` binary.\n */\nconst getPackageManagerCIConfig = (\n packageManager: PackageManager\n): PackageManagerCIConfig => {\n const setupNodeStep = (\n cache: PackageManager | undefined\n ): string => ` - name: 🟢 Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: 20${cache ? `\\n cache: ${cache}` : ''}`;\n\n switch (packageManager) {\n case 'bun':\n return {\n setupSteps: ` - name: 🥟 Setup Bun\n uses: oven-sh/setup-bun@v2`,\n installCommand: 'bun install --frozen-lockfile',\n execCommand: 'bunx intlayer',\n };\n case 'pnpm':\n return {\n setupSteps: ` - name: 📦 Setup pnpm\n uses: pnpm/action-setup@v4\n${setupNodeStep('pnpm')}`,\n installCommand: 'pnpm install --frozen-lockfile',\n execCommand: 'pnpm exec intlayer',\n };\n case 'yarn':\n return {\n setupSteps: setupNodeStep('yarn'),\n installCommand: 'yarn install --frozen-lockfile',\n execCommand: 'yarn intlayer',\n };\n case 'npm':\n return {\n setupSteps: setupNodeStep('npm'),\n installCommand: 'npm ci',\n execCommand: 'npx intlayer',\n };\n }\n};\n\n/**\n * Builds the `intlayer fill` workflow. Runs on pull requests, regenerates the\n * missing translations for the changed dictionaries (`--git-diff`) using AI,\n * then commits the result back to the PR branch.\n *\n * AI access is required for `fill`. The workflow exposes both options:\n * - a provider API key (`AI_API_KEY` secret), forwarded via CLI flags, or\n * - Intlayer CMS access keys (`INTLAYER_CLIENT_ID` / `INTLAYER_CLIENT_SECRET`).\n */\nconst generateFillWorkflow = (packageManager: PackageManager): string => {\n const { setupSteps, installCommand, execCommand } =\n getPackageManagerCIConfig(packageManager);\n\n return `name: Intlayer Fill\n# Auto-fill missing translations on every pull request.\non:\n pull_request:\n branches:\n - main\n\npermissions:\n contents: write\n pull-requests: write\n\nconcurrency:\n group: intlayer-fill-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n fill:\n runs-on: ubuntu-latest\n env:\n # AI access is required to generate translations.\n # Add the secret in: Settings → Secrets and variables → Actions.\n #\n # Option 1 — Use your own AI provider key (forwarded below via CLI flags):\n AI_PROVIDER: openai\n AI_MODEL: gpt-5-mini\n AI_API_KEY: \\${{ secrets.AI_API_KEY }}\n #\n # Option 2 — Use Intlayer CMS access keys instead of your own AI key.\n # Wire them in your intlayer.config and uncomment the lines below:\n # INTLAYER_CLIENT_ID: \\${{ secrets.INTLAYER_CLIENT_ID }}\n # INTLAYER_CLIENT_SECRET: \\${{ secrets.INTLAYER_CLIENT_SECRET }}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n with:\n persist-credentials: true # Keep credentials to push back to the PR\n fetch-depth: 0 # Full history so --git-diff can compare refs\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${execCommand} build\n - name: 🤖 Fill missing translations\n # Skip when no AI credentials are configured, so the workflow stays green\n # until an \\`AI_API_KEY\\` (or Intlayer CMS access keys) secret is added.\n if: \\${{ env.AI_API_KEY != '' || env.INTLAYER_CLIENT_ID != '' }}\n run: ${execCommand} fill --git-diff --mode complete --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY\n - name: 📤 Commit and push changes\n run: |\n git config --local user.email \"github-actions[bot]@users.noreply.github.com\"\n git config --local user.name \"github-actions[bot]\"\n if [ -n \"$(git status --porcelain)\" ]; then\n git add .\n git commit -m \"chore(intlayer): fill missing translations [skip ci]\"\n git push origin HEAD:\\${{ github.head_ref }}\n else\n echo \"No missing translations to fill.\"\n fi\n`;\n};\n\n/**\n * Builds the `intlayer test` workflow. Runs on pull requests and fails the\n * check when required locales are missing translations. No AI access needed.\n */\nconst generateTestWorkflow = (packageManager: PackageManager): string => {\n const { setupSteps, installCommand, execCommand } =\n getPackageManagerCIConfig(packageManager);\n\n return `name: Intlayer Test\n# Fail the pull request when required locales are missing translations.\non:\n pull_request:\n branches:\n - main\n\nconcurrency:\n group: intlayer-test-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${execCommand} build\n - name: 🧪 Test for missing translations\n run: ${execCommand} test\n`;\n};\n\n/** Workflow file path constants, relative to the project root. */\nexport const GITHUB_FILL_WORKFLOW_PATH = '.github/workflows/intlayer-fill.yml';\nexport const GITHUB_TEST_WORKFLOW_PATH = '.github/workflows/intlayer-test.yml';\n\n/**\n * Returns the two Intlayer GitHub Actions workflows (`fill` and `test`),\n * generated with commands matching the detected package manager.\n */\nexport const getGithubWorkflows = (\n packageManager: PackageManager\n): GithubWorkflowFile[] => [\n {\n filePath: GITHUB_FILL_WORKFLOW_PATH,\n content: generateFillWorkflow(packageManager),\n },\n {\n filePath: GITHUB_TEST_WORKFLOW_PATH,\n content: generateTestWorkflow(packageManager),\n },\n];\n"],"mappings":";;;;;;AA4BA,MAAM,6BACJ,mBAC2B;CAC3B,MAAM,iBACJ,UACW;;;4BAGa,QAAQ,sBAAsB,UAAU;AAElE,SAAQ,gBAAR;EACE,KAAK,MACH,QAAO;GACL,YAAY;;GAEZ,gBAAgB;GAChB,aAAa;GACd;EACH,KAAK,OACH,QAAO;GACL,YAAY;;EAElB,cAAc,OAAO;GACf,gBAAgB;GAChB,aAAa;GACd;EACH,KAAK,OACH,QAAO;GACL,YAAY,cAAc,OAAO;GACjC,gBAAgB;GAChB,aAAa;GACd;EACH,KAAK,MACH,QAAO;GACL,YAAY,cAAc,MAAM;GAChC,gBAAgB;GAChB,aAAa;GACd;;;;;;;;;;;;AAaP,MAAM,wBAAwB,mBAA2C;CACvE,MAAM,EAAE,YAAY,gBAAgB,gBAClC,0BAA0B,eAAe;AAE3C,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCP,WAAW;;eAEE,eAAe;;eAEf,YAAY;;;;;eAKZ,YAAY;;;;;;;;;;;;;;;;;;AAmB3B,MAAM,wBAAwB,mBAA2C;CACvE,MAAM,EAAE,YAAY,gBAAgB,gBAClC,0BAA0B,eAAe;AAE3C,QAAO;;;;;;;;;;;;;;;;;EAiBP,WAAW;;eAEE,eAAe;;eAEf,YAAY;;eAEZ,YAAY;;;;AAK3B,MAAa,4BAA4B;AACzC,MAAa,4BAA4B;;;;;AAMzC,MAAa,sBACX,mBACyB,CACzB;CACE,UAAU;CACV,SAAS,qBAAqB,eAAe;CAC9C,EACD;CACE,UAAU;CACV,SAAS,qBAAqB,eAAe;CAC9C,CACF"}
1
+ {"version":3,"file":"githubActions.mjs","names":[],"sources":["../../../../src/init/utils/githubActions.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\nimport { getGitRootDir, listProjects } from '../../listProjects';\nimport { detectPackageManager, type PackageManager } from './packageManager';\n\n/** A GitHub Actions workflow file to be written to the project. */\nexport type GithubWorkflowFile = {\n /** Path relative to the project root, e.g. `.github/workflows/intlayer-fill.yml`. */\n filePath: string;\n /** Full YAML content of the workflow file. */\n content: string;\n};\n\n/** Options controlling how the CI workflows are generated. */\nexport type GithubWorkflowsOptions = {\n /**\n * Route the intlayer commands through `intlayer ci` instead of calling them\n * directly. The `ci` command discovers every Intlayer project of the\n * repository (via `listProjects`) and runs the given command inside each of\n * them, injecting per-project credentials from the\n * `INTLAYER_PROJECT_CREDENTIALS` secret when provided. Required for\n * monorepos where a single workflow must cover several projects.\n */\n useCiCommand?: boolean;\n /**\n * Repository-relative directory (posix separators) the workflow commands run\n * in. Set when the Intlayer project lives in a subdirectory of the\n * repository and the repository root has no workspace manifest to install\n * dependencies from. Undefined = repository root.\n */\n workingDirectory?: string;\n};\n\n/**\n * Resolved placement and generation parameters for the CI workflows.\n * See {@link resolveGithubWorkflowsContext}.\n */\nexport type GithubWorkflowsContext = {\n /**\n * Directory the workflow files must be written to. GitHub only triggers\n * workflows stored in `.github/workflows` at the repository root, so this is\n * the git root whenever the project lives inside a git repository.\n */\n workflowsRootDir: string;\n /** Package manager whose commands are baked into the workflows. */\n packageManager: PackageManager;\n /** Generation options forwarded to {@link getGithubWorkflows}. */\n options: GithubWorkflowsOptions;\n};\n\n/**\n * Returns true when the repository root hosts a workspace manifest\n * (a `package.json` `workspaces` field or a `pnpm-workspace.yaml`), meaning a\n * single install at the root covers every package of the monorepo.\n */\nconst hasWorkspaceManifest = (repositoryRootDir: string): boolean => {\n if (existsSync(join(repositoryRootDir, 'pnpm-workspace.yaml'))) {\n return true;\n }\n\n try {\n const packageJsonPath = join(repositoryRootDir, 'package.json');\n if (!existsSync(packageJsonPath)) return false;\n const { workspaces } = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return Boolean(workspaces);\n } catch {\n return false;\n }\n};\n\n/**\n * Resolves where the CI workflows must be written and how their commands must\n * be generated, based on the repository layout around `rootDir` (the Intlayer\n * project being initialized):\n *\n * - Project at the repository root: workflows are written in place. When the\n * repository is a monorepo (workspace manifest, or several Intlayer projects\n * discovered by `listProjects`), the commands go through `intlayer ci` so\n * every project is covered.\n * - Project nested in a repository whose root has a `package.json`\n * (workspace-managed monorepo): workflows are written at the git root —\n * GitHub ignores `.github/workflows` in subdirectories — dependencies are\n * installed at the root with the root's package manager, and the commands go\n * through `intlayer ci` to iterate every Intlayer project.\n * - Project nested in a repository without a root `package.json`: workflows\n * are written at the git root but run inside the project directory\n * (`working-directory`), keeping the project's own package manager.\n */\nexport const resolveGithubWorkflowsContext = async (\n rootDir: string,\n projectPackageManager: PackageManager\n): Promise<GithubWorkflowsContext> => {\n const projectRootDir = resolve(rootDir);\n\n let repositoryRootDir = projectRootDir;\n try {\n const gitRootDir = await getGitRootDir(projectRootDir);\n if (gitRootDir) repositoryRootDir = resolve(gitRootDir);\n } catch {\n // Not a git repository — keep the project root as the workflow root.\n }\n\n // Discover every Intlayer project of the repository. `listProjects` scans\n // for configuration files, so a fresh project whose config is created later\n // in the init flow may not be counted yet — the workspace manifest check\n // below still catches that monorepo case.\n let repositoryProjectCount = 0;\n try {\n const { projectsPath } = await listProjects({\n baseDir: repositoryRootDir,\n });\n repositoryProjectCount = projectsPath.length;\n } catch {\n repositoryProjectCount = 0;\n }\n\n const isNestedProject = repositoryRootDir !== projectRootDir;\n const isWorkspaceRepository = hasWorkspaceManifest(repositoryRootDir);\n const hasRootPackageJson = existsSync(\n join(repositoryRootDir, 'package.json')\n );\n\n if (!isNestedProject) {\n return {\n workflowsRootDir: projectRootDir,\n packageManager: projectPackageManager,\n options: {\n useCiCommand: isWorkspaceRepository || repositoryProjectCount > 1,\n },\n };\n }\n\n if (hasRootPackageJson) {\n return {\n workflowsRootDir: repositoryRootDir,\n packageManager: detectPackageManager(repositoryRootDir),\n options: { useCiCommand: true },\n };\n }\n\n // Nested project without a root manifest: install and run everything inside\n // the project directory itself.\n return {\n workflowsRootDir: repositoryRootDir,\n packageManager: projectPackageManager,\n options: {\n workingDirectory: relative(repositoryRootDir, projectRootDir)\n .split(sep)\n .join('/'),\n },\n };\n};\n\n/**\n * Package-manager-specific snippets used to assemble the CI workflows.\n * - `setupSteps`: YAML steps (already indented for the `steps:` list) that\n * install the package manager and Node.js, including dependency caching.\n * - `installCommand`: command that installs the project dependencies.\n * - `execCommand`: prefix used to run the locally installed `intlayer` binary.\n */\ntype PackageManagerCIConfig = {\n setupSteps: string;\n installCommand: string;\n execCommand: string;\n};\n\n/** Dependency lock file of each package manager, used for cache invalidation. */\nconst LOCK_FILE_BY_PACKAGE_MANAGER: Record<PackageManager, string> = {\n bun: 'bun.lock',\n pnpm: 'pnpm-lock.yaml',\n yarn: 'yarn.lock',\n npm: 'package-lock.json',\n};\n\n/**\n * Returns the package-manager-specific steps and commands used to build the\n * GitHub Actions workflows. Each package manager needs a slightly different\n * setup action and a different way to run the local `intlayer` binary.\n *\n * `workingDirectory` is the repository-relative directory holding the lock\n * file when the project is nested: `actions/setup-node` looks for the lock\n * file at the repository root by default and fails the cache setup otherwise.\n */\nconst getPackageManagerCIConfig = (\n packageManager: PackageManager,\n workingDirectory?: string\n): PackageManagerCIConfig => {\n const setupNodeStep = (cache: PackageManager | undefined): string => {\n const cacheDependencyPath =\n cache && workingDirectory\n ? `\\n cache-dependency-path: ${workingDirectory}/${LOCK_FILE_BY_PACKAGE_MANAGER[cache]}`\n : '';\n\n return ` - name: 🟢 Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: 20${cache ? `\\n cache: ${cache}` : ''}${cacheDependencyPath}`;\n };\n\n switch (packageManager) {\n case 'bun':\n return {\n setupSteps: ` - name: 🥟 Setup Bun\n uses: oven-sh/setup-bun@v2`,\n installCommand: 'bun install --frozen-lockfile',\n execCommand: 'bunx intlayer',\n };\n case 'pnpm':\n return {\n setupSteps: ` - name: 📦 Setup pnpm\n uses: pnpm/action-setup@v4\n${setupNodeStep('pnpm')}`,\n installCommand: 'pnpm install --frozen-lockfile',\n execCommand: 'pnpm exec intlayer',\n };\n case 'yarn':\n return {\n setupSteps: setupNodeStep('yarn'),\n installCommand: 'yarn install --frozen-lockfile',\n execCommand: 'yarn intlayer',\n };\n case 'npm':\n return {\n setupSteps: setupNodeStep('npm'),\n installCommand: 'npm ci',\n execCommand: 'npx intlayer',\n };\n }\n};\n\n/**\n * Renders the `defaults.run.working-directory` block for jobs that must run\n * inside a nested project directory. Empty when the commands run at the\n * repository root.\n */\nconst getWorkingDirectoryBlock = (workingDirectory?: string): string =>\n workingDirectory\n ? `\n defaults:\n run:\n working-directory: ${workingDirectory}`\n : '';\n\n/**\n * Renders the env comment + optional wiring for per-project credentials in\n * monorepo (`intlayer ci`) mode. The `ci` command matches each entry of the\n * `INTLAYER_PROJECT_CREDENTIALS` JSON map to a discovered project path and\n * injects its access keys before running the command in that project.\n */\nconst getMonorepoCredentialsBlock = (useCiCommand?: boolean): string =>\n useCiCommand\n ? `\n #\n # Monorepo — per-project CMS credentials, as a JSON map of project path\n # (relative to the repository root) to access keys, e.g.\n # {\"apps/web\":{\"clientId\":\"...\",\"clientSecret\":\"...\"}}:\n # INTLAYER_PROJECT_CREDENTIALS: \\${{ secrets.INTLAYER_PROJECT_CREDENTIALS }}`\n : '';\n\n/**\n * Builds the `intlayer fill` workflow. Runs on pull requests, regenerates the\n * missing translations for the changed dictionaries (`--git-diff`) using AI,\n * then commits the result back to the PR branch.\n *\n * AI access is required for `fill`. The workflow exposes both options:\n * - a provider API key (`AI_API_KEY` secret), forwarded via CLI flags, or\n * - Intlayer CMS access keys (`INTLAYER_CLIENT_ID` / `INTLAYER_CLIENT_SECRET`).\n */\nconst generateFillWorkflow = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions\n): string => {\n const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(\n packageManager,\n options.workingDirectory\n );\n\n // In monorepo mode `intlayer ci <command>` discovers every Intlayer project\n // of the repository and runs the command inside each of them.\n const intlayerCommand = options.useCiCommand\n ? `${execCommand} ci`\n : execCommand;\n\n return `name: Intlayer Fill\n# Auto-fill missing translations on every pull request.\non:\n pull_request:\n branches:\n - main\n\npermissions:\n contents: write\n pull-requests: write\n\nconcurrency:\n group: intlayer-fill-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n fill:\n runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}\n env:\n # AI access is required to generate translations.\n # Add the secret in: Settings → Secrets and variables → Actions.\n #\n # Option 1 — Use your own AI provider key (forwarded below via CLI flags):\n AI_PROVIDER: openai\n AI_MODEL: gpt-5-mini\n AI_API_KEY: \\${{ secrets.AI_API_KEY }}\n #\n # Option 2 — Use Intlayer CMS access keys instead of your own AI key.\n # Wire them in your intlayer.config and uncomment the lines below:\n # INTLAYER_CLIENT_ID: \\${{ secrets.INTLAYER_CLIENT_ID }}\n # INTLAYER_CLIENT_SECRET: \\${{ secrets.INTLAYER_CLIENT_SECRET }}${getMonorepoCredentialsBlock(options.useCiCommand)}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n with:\n persist-credentials: true # Keep credentials to push back to the PR\n fetch-depth: 0 # Full history so --git-diff can compare refs\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${intlayerCommand} build\n - name: 🤖 Fill missing translations\n # Skip when no AI credentials are configured, so the workflow stays green\n # until an \\`AI_API_KEY\\` (or Intlayer CMS access keys) secret is added.\n if: \\${{ env.AI_API_KEY != '' || env.INTLAYER_CLIENT_ID != '' }}\n run: ${intlayerCommand} fill --git-diff --mode complete --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY\n - name: 📤 Commit and push changes\n run: |\n git config --local user.email \"github-actions[bot]@users.noreply.github.com\"\n git config --local user.name \"github-actions[bot]\"\n if [ -n \"$(git status --porcelain)\" ]; then\n git add .\n git commit -m \"chore(intlayer): fill missing translations [skip ci]\"\n git push origin HEAD:\\${{ github.head_ref }}\n else\n echo \"No missing translations to fill.\"\n fi\n`;\n};\n\n/**\n * Builds the `intlayer test` workflow. Runs on pull requests and fails the\n * check when required locales are missing translations. No AI access needed.\n */\nconst generateTestWorkflow = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions\n): string => {\n const { setupSteps, installCommand, execCommand } = getPackageManagerCIConfig(\n packageManager,\n options.workingDirectory\n );\n\n // In monorepo mode `intlayer ci <command>` discovers every Intlayer project\n // of the repository and runs the command inside each of them.\n const intlayerCommand = options.useCiCommand\n ? `${execCommand} ci`\n : execCommand;\n\n return `name: Intlayer Test\n# Fail the pull request when required locales are missing translations.\non:\n pull_request:\n branches:\n - main\n\nconcurrency:\n group: intlayer-test-\\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n test:\n runs-on: ubuntu-latest${getWorkingDirectoryBlock(options.workingDirectory)}\n steps:\n - name: ⬇️ Checkout repository\n uses: actions/checkout@v4\n${setupSteps}\n - name: 📦 Install dependencies\n run: ${installCommand}\n - name: ⚙️ Build dictionaries\n run: ${intlayerCommand} build\n - name: 🧪 Test for missing translations\n run: ${intlayerCommand} test\n`;\n};\n\n/** Workflow file path constants, relative to the project root. */\nexport const GITHUB_FILL_WORKFLOW_PATH = '.github/workflows/intlayer-fill.yml';\nexport const GITHUB_TEST_WORKFLOW_PATH = '.github/workflows/intlayer-test.yml';\n\n/**\n * Returns the two Intlayer GitHub Actions workflows (`fill` and `test`),\n * generated with commands matching the detected package manager and the\n * repository layout (see {@link GithubWorkflowsOptions} for the monorepo and\n * nested-project variants).\n */\nexport const getGithubWorkflows = (\n packageManager: PackageManager,\n options: GithubWorkflowsOptions = {}\n): GithubWorkflowFile[] => [\n {\n filePath: GITHUB_FILL_WORKFLOW_PATH,\n content: generateFillWorkflow(packageManager, options),\n },\n {\n filePath: GITHUB_TEST_WORKFLOW_PATH,\n content: generateTestWorkflow(packageManager, options),\n },\n];\n"],"mappings":";;;;;;;;;;;AAuDA,MAAM,wBAAwB,sBAAuC;AACnE,KAAI,WAAW,KAAK,mBAAmB,sBAAsB,CAAC,CAC5D,QAAO;AAGT,KAAI;EACF,MAAM,kBAAkB,KAAK,mBAAmB,eAAe;AAC/D,MAAI,CAAC,WAAW,gBAAgB,CAAE,QAAO;EACzC,MAAM,EAAE,eAAe,KAAK,MAAM,aAAa,iBAAiB,QAAQ,CAAC;AACzE,SAAO,QAAQ,WAAW;SACpB;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;AAsBX,MAAa,gCAAgC,OAC3C,SACA,0BACoC;CACpC,MAAM,iBAAiB,QAAQ,QAAQ;CAEvC,IAAI,oBAAoB;AACxB,KAAI;EACF,MAAM,aAAa,MAAM,cAAc,eAAe;AACtD,MAAI,WAAY,qBAAoB,QAAQ,WAAW;SACjD;CAQR,IAAI,yBAAyB;AAC7B,KAAI;EACF,MAAM,EAAE,iBAAiB,MAAM,aAAa,EAC1C,SAAS,mBACV,CAAC;AACF,2BAAyB,aAAa;SAChC;AACN,2BAAyB;;CAG3B,MAAM,kBAAkB,sBAAsB;CAC9C,MAAM,wBAAwB,qBAAqB,kBAAkB;CACrE,MAAM,qBAAqB,WACzB,KAAK,mBAAmB,eAAe,CACxC;AAED,KAAI,CAAC,gBACH,QAAO;EACL,kBAAkB;EAClB,gBAAgB;EAChB,SAAS,EACP,cAAc,yBAAyB,yBAAyB,GACjE;EACF;AAGH,KAAI,mBACF,QAAO;EACL,kBAAkB;EAClB,gBAAgB,qBAAqB,kBAAkB;EACvD,SAAS,EAAE,cAAc,MAAM;EAChC;AAKH,QAAO;EACL,kBAAkB;EAClB,gBAAgB;EAChB,SAAS,EACP,kBAAkB,SAAS,mBAAmB,eAAe,CAC1D,MAAM,IAAI,CACV,KAAK,IAAI,EACb;EACF;;;AAiBH,MAAM,+BAA+D;CACnE,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACN;;;;;;;;;;AAWD,MAAM,6BACJ,gBACA,qBAC2B;CAC3B,MAAM,iBAAiB,UAA8C;EACnE,MAAM,sBACJ,SAAS,mBACL,sCAAsC,iBAAiB,GAAG,6BAA6B,WACvF;AAEN,SAAO;;;4BAGiB,QAAQ,sBAAsB,UAAU,KAAK;;AAGvE,SAAQ,gBAAR;EACE,KAAK,MACH,QAAO;GACL,YAAY;;GAEZ,gBAAgB;GAChB,aAAa;GACd;EACH,KAAK,OACH,QAAO;GACL,YAAY;;EAElB,cAAc,OAAO;GACf,gBAAgB;GAChB,aAAa;GACd;EACH,KAAK,OACH,QAAO;GACL,YAAY,cAAc,OAAO;GACjC,gBAAgB;GAChB,aAAa;GACd;EACH,KAAK,MACH,QAAO;GACL,YAAY,cAAc,MAAM;GAChC,gBAAgB;GAChB,aAAa;GACd;;;;;;;;AASP,MAAM,4BAA4B,qBAChC,mBACI;;;6BAGuB,qBACvB;;;;;;;AAQN,MAAM,+BAA+B,iBACnC,eACI;;;;;sFAMA;;;;;;;;;;AAWN,MAAM,wBACJ,gBACA,YACW;CACX,MAAM,EAAE,YAAY,gBAAgB,gBAAgB,0BAClD,gBACA,QAAQ,iBACT;CAID,MAAM,kBAAkB,QAAQ,eAC5B,GAAG,YAAY,OACf;AAEJ,QAAO;;;;;;;;;;;;;;;;;4BAiBmB,yBAAyB,QAAQ,iBAAiB,CAAC;;;;;;;;;;;;;wEAaP,4BAA4B,QAAQ,aAAa,CAAC;;;;;;;EAOxH,WAAW;;eAEE,eAAe;;eAEf,gBAAgB;;;;;eAKhB,gBAAgB;;;;;;;;;;;;;;;;;;AAmB/B,MAAM,wBACJ,gBACA,YACW;CACX,MAAM,EAAE,YAAY,gBAAgB,gBAAgB,0BAClD,gBACA,QAAQ,iBACT;CAID,MAAM,kBAAkB,QAAQ,eAC5B,GAAG,YAAY,OACf;AAEJ,QAAO;;;;;;;;;;;;;4BAamB,yBAAyB,QAAQ,iBAAiB,CAAC;;;;EAI7E,WAAW;;eAEE,eAAe;;eAEf,gBAAgB;;eAEhB,gBAAgB;;;;AAK/B,MAAa,4BAA4B;AACzC,MAAa,4BAA4B;;;;;;;AAQzC,MAAa,sBACX,gBACA,UAAkC,EAAE,KACX,CACzB;CACE,UAAU;CACV,SAAS,qBAAqB,gBAAgB,QAAQ;CACvD,EACD;CACE,UAAU;CACV,SAAS,qBAAqB,gBAAgB,QAAQ;CACvD,CACF"}
@@ -2,10 +2,10 @@ import { ensureNamedImport, firstInsertIndex, isModuleScopeBinding } from "./ast
2
2
  import { enableIntlayerEditorConfig, getMetroConfigTemplate, hasIntlayerVitePlugin, replaceViteConfigPluginImportSource, setIntlayerConfigCompilerOutput, setIntlayerConfigRoutingMode, updateAstroConfig, updateIntlayerConfigWithSyncPlugin, updateMetroConfig, updateNextConfig, updateNextConfigForNextI18next, updateNextConfigForNextIntl, updateNextConfigForNextTranslate, updateNuxtConfig, updateNuxtConfigForNuxtjsI18n, updateViteConfig, updateViteConfigForCompatPlugin, updateViteConfigForVueI18n } from "./configManipulation.mjs";
3
3
  import { detectJsonLocalePattern, detectLinguiCatalogPattern, detectNextIntlMessagesPattern, ensureDirectory, exists, readFileFromRoot, writeFileToRoot } from "./fileSystem.mjs";
4
4
  import { isVersionAtLeast } from "./version.mjs";
5
- import { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, getGithubWorkflows } from "./githubActions.mjs";
6
- import { parseJSONWithComments } from "./jsonParser.mjs";
7
5
  import { detectMissingIntlayerPackages, detectOutdatedIntlayerPackages, detectPackageManager, getInstalledPackageVersion, installPackages, isIntlayerPackageName, normalizeVersion, upgradePackages } from "./packageManager.mjs";
6
+ import { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, getGithubWorkflows, resolveGithubWorkflowsContext } from "./githubActions.mjs";
7
+ import { parseJSONWithComments } from "./jsonParser.mjs";
8
8
  import { NEXT_INTLAYER_BABEL_CONFIG_CONTENT, setupNextCompilerBabelConfig } from "./nextCompilerBabel.mjs";
9
9
  import { findTsConfigFiles } from "./tsConfig.mjs";
10
10
 
11
- export { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, detectJsonLocalePattern, detectLinguiCatalogPattern, detectMissingIntlayerPackages, detectNextIntlMessagesPattern, detectOutdatedIntlayerPackages, detectPackageManager, enableIntlayerEditorConfig, ensureDirectory, ensureNamedImport, exists, findTsConfigFiles, firstInsertIndex, getGithubWorkflows, getInstalledPackageVersion, getMetroConfigTemplate, hasIntlayerVitePlugin, installPackages, isIntlayerPackageName, isModuleScopeBinding, isVersionAtLeast, normalizeVersion, parseJSONWithComments, readFileFromRoot, replaceViteConfigPluginImportSource, setIntlayerConfigCompilerOutput, setIntlayerConfigRoutingMode, setupNextCompilerBabelConfig, updateAstroConfig, updateIntlayerConfigWithSyncPlugin, updateMetroConfig, updateNextConfig, updateNextConfigForNextI18next, updateNextConfigForNextIntl, updateNextConfigForNextTranslate, updateNuxtConfig, updateNuxtConfigForNuxtjsI18n, updateViteConfig, updateViteConfigForCompatPlugin, updateViteConfigForVueI18n, upgradePackages, writeFileToRoot };
11
+ export { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, detectJsonLocalePattern, detectLinguiCatalogPattern, detectMissingIntlayerPackages, detectNextIntlMessagesPattern, detectOutdatedIntlayerPackages, detectPackageManager, enableIntlayerEditorConfig, ensureDirectory, ensureNamedImport, exists, findTsConfigFiles, firstInsertIndex, getGithubWorkflows, getInstalledPackageVersion, getMetroConfigTemplate, hasIntlayerVitePlugin, installPackages, isIntlayerPackageName, isModuleScopeBinding, isVersionAtLeast, normalizeVersion, parseJSONWithComments, readFileFromRoot, replaceViteConfigPluginImportSource, resolveGithubWorkflowsContext, setIntlayerConfigCompilerOutput, setIntlayerConfigRoutingMode, setupNextCompilerBabelConfig, updateAstroConfig, updateIntlayerConfigWithSyncPlugin, updateMetroConfig, updateNextConfig, updateNextConfigForNextI18next, updateNextConfigForNextIntl, updateNextConfigForNextTranslate, updateNuxtConfig, updateNuxtConfigForNuxtjsI18n, updateViteConfig, updateViteConfigForCompatPlugin, updateViteConfigForVueI18n, upgradePackages, writeFileToRoot };
@@ -5,7 +5,8 @@ import simpleGit from "simple-git";
5
5
 
6
6
  //#region src/listProjects.ts
7
7
  /**
8
- * Get the git root directory
8
+ * Returns the git repository root directory, or `null` when the given
9
+ * directory is not inside a git repository.
9
10
  */
10
11
  const getGitRootDir = async (cwd) => {
11
12
  try {
@@ -40,5 +41,5 @@ const listProjects = async (options) => {
40
41
  };
41
42
 
42
43
  //#endregion
43
- export { listProjects };
44
+ export { getGitRootDir, listProjects };
44
45
  //# sourceMappingURL=listProjects.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"listProjects.mjs","names":[],"sources":["../../src/listProjects.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { configurationFilesCandidates } from '@intlayer/config/node';\nimport fg from 'fast-glob';\nimport simpleGit from 'simple-git';\n\nexport type ListProjectsOptions = {\n /**\n * Base directory to search from\n * @default process.cwd()\n */\n baseDir?: string;\n /**\n * If true, search from the git root directory instead of baseDir\n * @default false\n */\n gitRoot?: boolean;\n};\n\n/**\n * Get the git root directory\n */\nconst getGitRootDir = async (cwd?: string): Promise<string | null> => {\n try {\n const git = cwd ? simpleGit(cwd) : simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (_error) {\n return null;\n }\n};\n\n/**\n * List all Intlayer projects by searching for configuration files\n *\n * @param options - Options for listing projects\n * @returns Array of absolute paths to project directories containing Intlayer config\n */\nexport const listProjects = async (\n options?: ListProjectsOptions\n): Promise<{ searchDir: string; projectsPath: string[] }> => {\n let searchDir = options?.baseDir ?? process.cwd();\n\n // If gitRoot option is enabled, try to get the git root directory\n if (options?.gitRoot) {\n const gitRootDir = await getGitRootDir(searchDir);\n if (gitRootDir) {\n searchDir = gitRootDir;\n }\n }\n\n // Build glob patterns for all config file candidates\n const configPatterns = configurationFilesCandidates.map(\n (fileName) => `**/${fileName}`\n );\n\n // Search for all config files\n const configFiles = await fg(configPatterns, {\n cwd: searchDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true, // Include dot files like .intlayerrc\n });\n\n // Extract unique directory paths from config files\n const projectDirs = [...new Set(configFiles.map((file) => dirname(file)))];\n\n // Sort alphabetically for consistent output\n return { searchDir, projectsPath: projectDirs.sort() };\n};\n"],"mappings":";;;;;;;;;AAqBA,MAAM,gBAAgB,OAAO,QAAyC;AACpE,KAAI;AAGF,UAAO,OAFK,MAAM,UAAU,IAAI,GAAG,WAAW,EACpB,SAAS,CAAC,kBAAkB,CAAC,EACxC,MAAM;UACd,QAAQ;AACf,SAAO;;;;;;;;;AAUX,MAAa,eAAe,OAC1B,YAC2D;CAC3D,IAAI,YAAY,SAAS,WAAW,QAAQ,KAAK;AAGjD,KAAI,SAAS,SAAS;EACpB,MAAM,aAAa,MAAM,cAAc,UAAU;AACjD,MAAI,WACF,aAAY;;CAUhB,MAAM,cAAc,MAAM,GALH,6BAA6B,KACjD,aAAa,MAAM,WAIqB,EAAE;EAC3C,KAAK;EACL,UAAU;EACV,QAAQ,CAAC,sBAAsB,aAAa;EAC5C,KAAK;EACN,CAAC;CAGF,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,KAAK,SAAS,QAAQ,KAAK,CAAC,CAAC,CAAC;AAG1E,QAAO;EAAE;EAAW,cAAc,YAAY,MAAM;EAAE"}
1
+ {"version":3,"file":"listProjects.mjs","names":[],"sources":["../../src/listProjects.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { configurationFilesCandidates } from '@intlayer/config/node';\nimport fg from 'fast-glob';\nimport simpleGit from 'simple-git';\n\nexport type ListProjectsOptions = {\n /**\n * Base directory to search from\n * @default process.cwd()\n */\n baseDir?: string;\n /**\n * If true, search from the git root directory instead of baseDir\n * @default false\n */\n gitRoot?: boolean;\n};\n\n/**\n * Returns the git repository root directory, or `null` when the given\n * directory is not inside a git repository.\n */\nexport const getGitRootDir = async (cwd?: string): Promise<string | null> => {\n try {\n const git = cwd ? simpleGit(cwd) : simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (_error) {\n return null;\n }\n};\n\n/**\n * List all Intlayer projects by searching for configuration files\n *\n * @param options - Options for listing projects\n * @returns Array of absolute paths to project directories containing Intlayer config\n */\nexport const listProjects = async (\n options?: ListProjectsOptions\n): Promise<{ searchDir: string; projectsPath: string[] }> => {\n let searchDir = options?.baseDir ?? process.cwd();\n\n // If gitRoot option is enabled, try to get the git root directory\n if (options?.gitRoot) {\n const gitRootDir = await getGitRootDir(searchDir);\n if (gitRootDir) {\n searchDir = gitRootDir;\n }\n }\n\n // Build glob patterns for all config file candidates\n const configPatterns = configurationFilesCandidates.map(\n (fileName) => `**/${fileName}`\n );\n\n // Search for all config files\n const configFiles = await fg(configPatterns, {\n cwd: searchDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true, // Include dot files like .intlayerrc\n });\n\n // Extract unique directory paths from config files\n const projectDirs = [...new Set(configFiles.map((file) => dirname(file)))];\n\n // Sort alphabetically for consistent output\n return { searchDir, projectsPath: projectDirs.sort() };\n};\n"],"mappings":";;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,QAAyC;AAC3E,KAAI;AAGF,UAAO,OAFK,MAAM,UAAU,IAAI,GAAG,WAAW,EACpB,SAAS,CAAC,kBAAkB,CAAC,EACxC,MAAM;UACd,QAAQ;AACf,SAAO;;;;;;;;;AAUX,MAAa,eAAe,OAC1B,YAC2D;CAC3D,IAAI,YAAY,SAAS,WAAW,QAAQ,KAAK;AAGjD,KAAI,SAAS,SAAS;EACpB,MAAM,aAAa,MAAM,cAAc,UAAU;AACjD,MAAI,WACF,aAAY;;CAUhB,MAAM,cAAc,MAAM,GALH,6BAA6B,KACjD,aAAa,MAAM,WAIqB,EAAE;EAC3C,KAAK;EACL,UAAU;EACV,QAAQ,CAAC,sBAAsB,aAAa;EAC5C,KAAK;EACN,CAAC;CAGF,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,KAAK,SAAS,QAAQ,KAAK,CAAC,CAAC,CAAC;AAG1E,QAAO;EAAE;EAAW,cAAc,YAAY,MAAM;EAAE"}
@@ -1,10 +1,11 @@
1
1
  //#region src/writeConfiguration/generateConfigurationContent.ts
2
2
  const generateConfigurationContent = (configuration, format) => {
3
- const { internationalization, routing, editor, log, system, content, ai, dictionary, build, compiler } = configuration;
3
+ const { internationalization, routing, editor, analytics, log, system, content, ai, dictionary, build, compiler } = configuration;
4
4
  let fileContent = "";
5
5
  fileContent += `const internationalization = ${JSON.stringify(internationalization, null, 2)};\n`;
6
6
  fileContent += `const routing = ${JSON.stringify(routing, null, 2)};\n`;
7
7
  fileContent += `const editor = ${JSON.stringify(editor, null, 2)};\n`;
8
+ fileContent += `const analytics = ${JSON.stringify(analytics, null, 2)};\n`;
8
9
  fileContent += `const log = ${JSON.stringify(log, null, 2)};\n`;
9
10
  fileContent += `const system = ${JSON.stringify(system, null, 2)};\n`;
10
11
  fileContent += `const content = ${JSON.stringify(content, null, 2)};\n`;
@@ -12,11 +13,12 @@ const generateConfigurationContent = (configuration, format) => {
12
13
  fileContent += `const dictionary = ${JSON.stringify(dictionary, null, 2)};\n`;
13
14
  fileContent += `const build = ${JSON.stringify(build, null, 2)};\n`;
14
15
  fileContent += `const compiler = ${JSON.stringify(compiler, null, 2)};\n`;
15
- if (format === "esm") fileContent += `\nexport { internationalization, routing, editor, log, system, content, ai, dictionary, build, compiler };\n`;
16
+ if (format === "esm") fileContent += `\nexport { internationalization, routing, editor, analytics, log, system, content, ai, dictionary, build, compiler };\n`;
16
17
  else {
17
18
  fileContent += `\nmodule.exports.internationalization = internationalization;\n`;
18
19
  fileContent += `module.exports.routing = routing;\n`;
19
20
  fileContent += `module.exports.editor = editor;\n`;
21
+ fileContent += `module.exports.analytics = analytics;\n`;
20
22
  fileContent += `module.exports.log = log;\n`;
21
23
  fileContent += `module.exports.system = system;\n`;
22
24
  fileContent += `module.exports.content = content;\n`;
@@ -1 +1 @@
1
- {"version":3,"file":"generateConfigurationContent.mjs","names":[],"sources":["../../../src/writeConfiguration/generateConfigurationContent.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\n\nexport const generateConfigurationContent = (\n configuration: IntlayerConfig,\n format: 'cjs' | 'esm'\n): string => {\n const {\n internationalization,\n routing,\n editor,\n log,\n system,\n content,\n ai,\n dictionary,\n build,\n compiler,\n } = configuration;\n\n let fileContent = '';\n\n fileContent += `const internationalization = ${JSON.stringify(internationalization, null, 2)};\\n`;\n fileContent += `const routing = ${JSON.stringify(routing, null, 2)};\\n`;\n fileContent += `const editor = ${JSON.stringify(editor, null, 2)};\\n`;\n fileContent += `const log = ${JSON.stringify(log, null, 2)};\\n`;\n fileContent += `const system = ${JSON.stringify(system, null, 2)};\\n`;\n fileContent += `const content = ${JSON.stringify(content, null, 2)};\\n`;\n fileContent += `const ai = ${JSON.stringify(ai, null, 2)};\\n`;\n fileContent += `const dictionary = ${JSON.stringify(dictionary, null, 2)};\\n`;\n fileContent += `const build = ${JSON.stringify(build, null, 2)};\\n`;\n fileContent += `const compiler = ${JSON.stringify(compiler, null, 2)};\\n`;\n\n if (format === 'esm') {\n fileContent += `\\nexport { internationalization, routing, editor, log, system, content, ai, dictionary, build, compiler };\\n`;\n } else {\n fileContent += `\\nmodule.exports.internationalization = internationalization;\\n`;\n fileContent += `module.exports.routing = routing;\\n`;\n fileContent += `module.exports.editor = editor;\\n`;\n fileContent += `module.exports.log = log;\\n`;\n fileContent += `module.exports.system = system;\\n`;\n fileContent += `module.exports.content = content;\\n`;\n fileContent += `module.exports.ai = ai;\\n`;\n fileContent += `module.exports.dictionary = dictionary;\\n`;\n fileContent += `module.exports.build = build;\\n`;\n fileContent += `module.exports.compiler = compiler;\\n`;\n }\n\n return fileContent;\n};\n"],"mappings":";AAEA,MAAa,gCACX,eACA,WACW;CACX,MAAM,EACJ,sBACA,SACA,QACA,KACA,QACA,SACA,IACA,YACA,OACA,aACE;CAEJ,IAAI,cAAc;AAElB,gBAAe,gCAAgC,KAAK,UAAU,sBAAsB,MAAM,EAAE,CAAC;AAC7F,gBAAe,mBAAmB,KAAK,UAAU,SAAS,MAAM,EAAE,CAAC;AACnE,gBAAe,kBAAkB,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACjE,gBAAe,eAAe,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC;AAC3D,gBAAe,kBAAkB,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACjE,gBAAe,mBAAmB,KAAK,UAAU,SAAS,MAAM,EAAE,CAAC;AACnE,gBAAe,cAAc,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC;AACzD,gBAAe,sBAAsB,KAAK,UAAU,YAAY,MAAM,EAAE,CAAC;AACzE,gBAAe,iBAAiB,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;AAC/D,gBAAe,oBAAoB,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;AAErE,KAAI,WAAW,MACb,gBAAe;MACV;AACL,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;;AAGjB,QAAO"}
1
+ {"version":3,"file":"generateConfigurationContent.mjs","names":[],"sources":["../../../src/writeConfiguration/generateConfigurationContent.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\n\nexport const generateConfigurationContent = (\n configuration: IntlayerConfig,\n format: 'cjs' | 'esm'\n): string => {\n const {\n internationalization,\n routing,\n editor,\n analytics,\n log,\n system,\n content,\n ai,\n dictionary,\n build,\n compiler,\n } = configuration;\n\n let fileContent = '';\n\n fileContent += `const internationalization = ${JSON.stringify(internationalization, null, 2)};\\n`;\n fileContent += `const routing = ${JSON.stringify(routing, null, 2)};\\n`;\n fileContent += `const editor = ${JSON.stringify(editor, null, 2)};\\n`;\n fileContent += `const analytics = ${JSON.stringify(analytics, null, 2)};\\n`;\n fileContent += `const log = ${JSON.stringify(log, null, 2)};\\n`;\n fileContent += `const system = ${JSON.stringify(system, null, 2)};\\n`;\n fileContent += `const content = ${JSON.stringify(content, null, 2)};\\n`;\n fileContent += `const ai = ${JSON.stringify(ai, null, 2)};\\n`;\n fileContent += `const dictionary = ${JSON.stringify(dictionary, null, 2)};\\n`;\n fileContent += `const build = ${JSON.stringify(build, null, 2)};\\n`;\n fileContent += `const compiler = ${JSON.stringify(compiler, null, 2)};\\n`;\n\n if (format === 'esm') {\n fileContent += `\\nexport { internationalization, routing, editor, analytics, log, system, content, ai, dictionary, build, compiler };\\n`;\n } else {\n fileContent += `\\nmodule.exports.internationalization = internationalization;\\n`;\n fileContent += `module.exports.routing = routing;\\n`;\n fileContent += `module.exports.editor = editor;\\n`;\n fileContent += `module.exports.analytics = analytics;\\n`;\n fileContent += `module.exports.log = log;\\n`;\n fileContent += `module.exports.system = system;\\n`;\n fileContent += `module.exports.content = content;\\n`;\n fileContent += `module.exports.ai = ai;\\n`;\n fileContent += `module.exports.dictionary = dictionary;\\n`;\n fileContent += `module.exports.build = build;\\n`;\n fileContent += `module.exports.compiler = compiler;\\n`;\n }\n\n return fileContent;\n};\n"],"mappings":";AAEA,MAAa,gCACX,eACA,WACW;CACX,MAAM,EACJ,sBACA,SACA,QACA,WACA,KACA,QACA,SACA,IACA,YACA,OACA,aACE;CAEJ,IAAI,cAAc;AAElB,gBAAe,gCAAgC,KAAK,UAAU,sBAAsB,MAAM,EAAE,CAAC;AAC7F,gBAAe,mBAAmB,KAAK,UAAU,SAAS,MAAM,EAAE,CAAC;AACnE,gBAAe,kBAAkB,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACjE,gBAAe,qBAAqB,KAAK,UAAU,WAAW,MAAM,EAAE,CAAC;AACvE,gBAAe,eAAe,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC;AAC3D,gBAAe,kBAAkB,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACjE,gBAAe,mBAAmB,KAAK,UAAU,SAAS,MAAM,EAAE,CAAC;AACnE,gBAAe,cAAc,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC;AACzD,gBAAe,sBAAsB,KAAK,UAAU,YAAY,MAAM,EAAE,CAAC;AACzE,gBAAe,iBAAiB,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;AAC/D,gBAAe,oBAAoB,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;AAErE,KAAI,WAAW,MACb,gBAAe;MACV;AACL,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;AACf,iBAAe;;AAGjB,QAAO"}
@@ -16,6 +16,6 @@ import { PLATFORMS, PLATFORMS_METADATA, Platform, PlatformMetadata, SKILLS, SKIL
16
16
  import { MCPTransport, installMCP } from "./installMCP/installMCP.js";
17
17
  import { listDictionaries, listDictionariesWithStats } from "./listDictionariesPath.js";
18
18
  import { DiffMode, ListGitFilesOptions, ListGitLinesOptions, listGitFiles, listGitLines } from "./listGitFiles.js";
19
- import { ListProjectsOptions, listProjects } from "./listProjects.js";
19
+ import { ListProjectsOptions, getGitRootDir, listProjects } from "./listProjects.js";
20
20
  import { logConfigDetails } from "./logConfigDetails.js";
21
- export { type CmsCredentials, ContentStrategy, DictionaryStatus, DiffMode, InitOptions, ListGitFilesOptions, ListGitLinesOptions, ListProjectsOptions, MCPTransport, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, PLATFORMS, PLATFORMS_METADATA, type PackageManager, Platform, PlatformMetadata, type RoutingMode, SKILLS, SKILLS_METADATA, Skill, detectExportedComponentName, detectFormatCommand, detectPackageManager, enableEditorInConfig, getContentDeclarationFileTemplate, getDefaultApplicationURL, getInitialSkills, initIntlayer, installLSP, installMCP, installPackages, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, prepareIntlayer, setupCmsCredentials, transformJSFile, writeCmsCredentialsToEnv, writeContentDeclaration, writeJSFile };
21
+ export { type CmsCredentials, ContentStrategy, DictionaryStatus, DiffMode, InitOptions, ListGitFilesOptions, ListGitLinesOptions, ListProjectsOptions, MCPTransport, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, PLATFORMS, PLATFORMS_METADATA, type PackageManager, Platform, PlatformMetadata, type RoutingMode, SKILLS, SKILLS_METADATA, Skill, detectExportedComponentName, detectFormatCommand, detectPackageManager, enableEditorInConfig, getContentDeclarationFileTemplate, getDefaultApplicationURL, getGitRootDir, getInitialSkills, initIntlayer, installLSP, installMCP, installPackages, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, prepareIntlayer, setupCmsCredentials, transformJSFile, writeCmsCredentialsToEnv, writeContentDeclaration, writeJSFile };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/init/index.ts"],"mappings":";;;;;AA4LA;;;cAAa,wBAAA,GACX,YAAA,EAAc,MAAA;;AAsBhB;;;;;AAQA;;;KARY,eAAA;;;;KAQA,WAAA;EACV,WAAA,YAEA;EAAA,eAAA;EAMA;;;EAFA,iBAAA,YAqBA;EAnBA,iBAAA,YA0BA;EAxBA,KAAA;EA+BA;;;;EA1BA,gBAAA;EA2gCD;;;;;EArgCC,gBAAA;EA0BuE;;;;;EApBvE,WAAA,GAAc,WAAA;;;;;;;EAOd,gBAAA,GAAmB,MAAA;;;;;;;EAOnB,eAAA,GAAkB,eAAA;AAAA;;;;cAMP,YAAA,GAAsB,OAAA,UAAiB,OAAA,GAAU,WAAA,KAAW,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/init/index.ts"],"mappings":";;;;;AA6LA;;;cAAa,wBAAA,GACX,YAAA,EAAc,MAAA;;AAsBhB;;;;;AAQA;;;KARY,eAAA;;;;KAQA,WAAA;EACV,WAAA,YAEA;EAAA,eAAA;EAMA;;;EAFA,iBAAA,YAqBA;EAnBA,iBAAA,YA0BA;EAxBA,KAAA;EA+BA;;;;EA1BA,gBAAA;EA6hCD;;;;;EAvhCC,gBAAA;EA0BuE;;;;;EApBvE,WAAA,GAAc,WAAA;;;;;;;EAOd,gBAAA,GAAmB,MAAA;;;;;;;EAOnB,eAAA,GAAkB,eAAA;AAAA;;;;cAMP,YAAA,GAAsB,OAAA,UAAiB,OAAA,GAAU,WAAA,KAAW,OAAA"}
@@ -6,14 +6,68 @@ type GithubWorkflowFile = {
6
6
  /** Path relative to the project root, e.g. `.github/workflows/intlayer-fill.yml`. */filePath: string; /** Full YAML content of the workflow file. */
7
7
  content: string;
8
8
  };
9
+ /** Options controlling how the CI workflows are generated. */
10
+ type GithubWorkflowsOptions = {
11
+ /**
12
+ * Route the intlayer commands through `intlayer ci` instead of calling them
13
+ * directly. The `ci` command discovers every Intlayer project of the
14
+ * repository (via `listProjects`) and runs the given command inside each of
15
+ * them, injecting per-project credentials from the
16
+ * `INTLAYER_PROJECT_CREDENTIALS` secret when provided. Required for
17
+ * monorepos where a single workflow must cover several projects.
18
+ */
19
+ useCiCommand?: boolean;
20
+ /**
21
+ * Repository-relative directory (posix separators) the workflow commands run
22
+ * in. Set when the Intlayer project lives in a subdirectory of the
23
+ * repository and the repository root has no workspace manifest to install
24
+ * dependencies from. Undefined = repository root.
25
+ */
26
+ workingDirectory?: string;
27
+ };
28
+ /**
29
+ * Resolved placement and generation parameters for the CI workflows.
30
+ * See {@link resolveGithubWorkflowsContext}.
31
+ */
32
+ type GithubWorkflowsContext = {
33
+ /**
34
+ * Directory the workflow files must be written to. GitHub only triggers
35
+ * workflows stored in `.github/workflows` at the repository root, so this is
36
+ * the git root whenever the project lives inside a git repository.
37
+ */
38
+ workflowsRootDir: string; /** Package manager whose commands are baked into the workflows. */
39
+ packageManager: PackageManager; /** Generation options forwarded to {@link getGithubWorkflows}. */
40
+ options: GithubWorkflowsOptions;
41
+ };
42
+ /**
43
+ * Resolves where the CI workflows must be written and how their commands must
44
+ * be generated, based on the repository layout around `rootDir` (the Intlayer
45
+ * project being initialized):
46
+ *
47
+ * - Project at the repository root: workflows are written in place. When the
48
+ * repository is a monorepo (workspace manifest, or several Intlayer projects
49
+ * discovered by `listProjects`), the commands go through `intlayer ci` so
50
+ * every project is covered.
51
+ * - Project nested in a repository whose root has a `package.json`
52
+ * (workspace-managed monorepo): workflows are written at the git root —
53
+ * GitHub ignores `.github/workflows` in subdirectories — dependencies are
54
+ * installed at the root with the root's package manager, and the commands go
55
+ * through `intlayer ci` to iterate every Intlayer project.
56
+ * - Project nested in a repository without a root `package.json`: workflows
57
+ * are written at the git root but run inside the project directory
58
+ * (`working-directory`), keeping the project's own package manager.
59
+ */
60
+ declare const resolveGithubWorkflowsContext: (rootDir: string, projectPackageManager: PackageManager) => Promise<GithubWorkflowsContext>;
9
61
  /** Workflow file path constants, relative to the project root. */
10
62
  declare const GITHUB_FILL_WORKFLOW_PATH = ".github/workflows/intlayer-fill.yml";
11
63
  declare const GITHUB_TEST_WORKFLOW_PATH = ".github/workflows/intlayer-test.yml";
12
64
  /**
13
65
  * Returns the two Intlayer GitHub Actions workflows (`fill` and `test`),
14
- * generated with commands matching the detected package manager.
66
+ * generated with commands matching the detected package manager and the
67
+ * repository layout (see {@link GithubWorkflowsOptions} for the monorepo and
68
+ * nested-project variants).
15
69
  */
16
- declare const getGithubWorkflows: (packageManager: PackageManager) => GithubWorkflowFile[];
70
+ declare const getGithubWorkflows: (packageManager: PackageManager, options?: GithubWorkflowsOptions) => GithubWorkflowFile[];
17
71
  //#endregion
18
- export { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, GithubWorkflowFile, getGithubWorkflows };
72
+ export { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, GithubWorkflowFile, GithubWorkflowsContext, GithubWorkflowsOptions, getGithubWorkflows, resolveGithubWorkflowsContext };
19
73
  //# sourceMappingURL=githubActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"githubActions.d.ts","names":[],"sources":["../../../../src/init/utils/githubActions.ts"],"mappings":";;;;KAGY,kBAAA;EAAA,qFAEV,QAAA;EAEA,OAAA;AAAA;AA4KF;AAAA,cAAa,yBAAA;AAAA,cACA,yBAAA;;;AAAb;;cAMa,kBAAA,GACX,cAAA,EAAgB,cAAA,KACf,kBAAA"}
1
+ {"version":3,"file":"githubActions.d.ts","names":[],"sources":["../../../../src/init/utils/githubActions.ts"],"mappings":";;;;KAMY,kBAAA;EAAA,qFAEV,QAAA;EAEA,OAAA;AAAA;AAIF;AAAA,KAAY,sBAAA;;;;AAuBZ;;;;;EAdE,YAAA;EAsBgB;;;;;AA2ClB;EA1DE,gBAAA;AAAA;;;;;KAOU,sBAAA;EAoDV;;;;;EA9CA,gBAAA,UAgD+B;EA9C/B,cAAA,EAAgB,cAAA,EA0VoB;EAxVpC,OAAA,EAAS,sBAAA;AAAA;;AAyVX;;;;;AAQA;;;;;;;;;;;;cAxTa,6BAAA,GACX,OAAA,UACA,qBAAA,EAAuB,cAAA,KACtB,OAAA,CAAQ,sBAAA;;cA4SE,yBAAA;AAAA,cACA,yBAAA;;;;;;;cAQA,kBAAA,GACX,cAAA,EAAgB,cAAA,EAChB,OAAA,GAAS,sBAAA,KACR,kBAAA"}
@@ -2,9 +2,9 @@ import { CompatSyncConfig, CompatVitePluginConfig, DetectMissingPackagesOptions,
2
2
  import { RoutingMode, enableIntlayerEditorConfig, getMetroConfigTemplate, hasIntlayerVitePlugin, replaceViteConfigPluginImportSource, setIntlayerConfigCompilerOutput, setIntlayerConfigRoutingMode, updateAstroConfig, updateIntlayerConfigWithSyncPlugin, updateMetroConfig, updateNextConfig, updateNextConfigForNextI18next, updateNextConfigForNextIntl, updateNextConfigForNextTranslate, updateNuxtConfig, updateNuxtConfigForNuxtjsI18n, updateViteConfig, updateViteConfigForCompatPlugin, updateViteConfigForVueI18n } from "./configManipulation.js";
3
3
  import { ensureNamedImport, firstInsertIndex, isModuleScopeBinding } from "./astImports.js";
4
4
  import { JsonLocalePattern, JsonLocalePatternType, LinguiCatalogPattern, NextIntlMessagesPattern, detectJsonLocalePattern, detectLinguiCatalogPattern, detectNextIntlMessagesPattern, ensureDirectory, exists, readFileFromRoot, writeFileToRoot } from "./fileSystem.js";
5
- import { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, GithubWorkflowFile, getGithubWorkflows } from "./githubActions.js";
5
+ import { GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, GithubWorkflowFile, GithubWorkflowsContext, GithubWorkflowsOptions, getGithubWorkflows, resolveGithubWorkflowsContext } from "./githubActions.js";
6
6
  import { parseJSONWithComments } from "./jsonParser.js";
7
7
  import { NEXT_INTLAYER_BABEL_CONFIG_CONTENT, setupNextCompilerBabelConfig } from "./nextCompilerBabel.js";
8
8
  import { findTsConfigFiles } from "./tsConfig.js";
9
9
  import { isVersionAtLeast } from "./version.js";
10
- export { CompatSyncConfig, CompatVitePluginConfig, DetectMissingPackagesOptions, GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, GithubWorkflowFile, IntlayerPackageAnalysis, JsonLocalePattern, JsonLocalePatternType, LinguiCatalogPattern, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, NextIntlMessagesPattern, PackageManager, RoutingMode, detectJsonLocalePattern, detectLinguiCatalogPattern, detectMissingIntlayerPackages, detectNextIntlMessagesPattern, detectOutdatedIntlayerPackages, detectPackageManager, enableIntlayerEditorConfig, ensureDirectory, ensureNamedImport, exists, findTsConfigFiles, firstInsertIndex, getGithubWorkflows, getInstalledPackageVersion, getMetroConfigTemplate, hasIntlayerVitePlugin, installPackages, isIntlayerPackageName, isModuleScopeBinding, isVersionAtLeast, normalizeVersion, parseJSONWithComments, readFileFromRoot, replaceViteConfigPluginImportSource, setIntlayerConfigCompilerOutput, setIntlayerConfigRoutingMode, setupNextCompilerBabelConfig, updateAstroConfig, updateIntlayerConfigWithSyncPlugin, updateMetroConfig, updateNextConfig, updateNextConfigForNextI18next, updateNextConfigForNextIntl, updateNextConfigForNextTranslate, updateNuxtConfig, updateNuxtConfigForNuxtjsI18n, updateViteConfig, updateViteConfigForCompatPlugin, updateViteConfigForVueI18n, upgradePackages, writeFileToRoot };
10
+ export { CompatSyncConfig, CompatVitePluginConfig, DetectMissingPackagesOptions, GITHUB_FILL_WORKFLOW_PATH, GITHUB_TEST_WORKFLOW_PATH, GithubWorkflowFile, GithubWorkflowsContext, GithubWorkflowsOptions, IntlayerPackageAnalysis, JsonLocalePattern, JsonLocalePatternType, LinguiCatalogPattern, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, NextIntlMessagesPattern, PackageManager, RoutingMode, detectJsonLocalePattern, detectLinguiCatalogPattern, detectMissingIntlayerPackages, detectNextIntlMessagesPattern, detectOutdatedIntlayerPackages, detectPackageManager, enableIntlayerEditorConfig, ensureDirectory, ensureNamedImport, exists, findTsConfigFiles, firstInsertIndex, getGithubWorkflows, getInstalledPackageVersion, getMetroConfigTemplate, hasIntlayerVitePlugin, installPackages, isIntlayerPackageName, isModuleScopeBinding, isVersionAtLeast, normalizeVersion, parseJSONWithComments, readFileFromRoot, replaceViteConfigPluginImportSource, resolveGithubWorkflowsContext, setIntlayerConfigCompilerOutput, setIntlayerConfigRoutingMode, setupNextCompilerBabelConfig, updateAstroConfig, updateIntlayerConfigWithSyncPlugin, updateMetroConfig, updateNextConfig, updateNextConfigForNextI18next, updateNextConfigForNextIntl, updateNextConfigForNextTranslate, updateNuxtConfig, updateNuxtConfigForNuxtjsI18n, updateViteConfig, updateViteConfigForCompatPlugin, updateViteConfigForVueI18n, upgradePackages, writeFileToRoot };
@@ -11,6 +11,11 @@ type ListProjectsOptions = {
11
11
  */
12
12
  gitRoot?: boolean;
13
13
  };
14
+ /**
15
+ * Returns the git repository root directory, or `null` when the given
16
+ * directory is not inside a git repository.
17
+ */
18
+ declare const getGitRootDir: (cwd?: string) => Promise<string | null>;
14
19
  /**
15
20
  * List all Intlayer projects by searching for configuration files
16
21
  *
@@ -22,5 +27,5 @@ declare const listProjects: (options?: ListProjectsOptions) => Promise<{
22
27
  projectsPath: string[];
23
28
  }>;
24
29
  //#endregion
25
- export { ListProjectsOptions, listProjects };
30
+ export { ListProjectsOptions, getGitRootDir, listProjects };
26
31
  //# sourceMappingURL=listProjects.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"listProjects.d.ts","names":[],"sources":["../../src/listProjects.ts"],"mappings":";KAKY,mBAAA;EAAA;;;;EAKV,OAAA;EA2BW;;;;EAtBX,OAAA;AAAA;;;;;;;cAsBW,YAAA,GACX,OAAA,GAAU,mBAAA,KACT,OAAA;EAAU,SAAA;EAAmB,YAAA;AAAA"}
1
+ {"version":3,"file":"listProjects.d.ts","names":[],"sources":["../../src/listProjects.ts"],"mappings":";KAKY,mBAAA;EAAA;;;;EAKV,OAAA;EAYW;;;;EAPX,OAAA;AAAA;;;;;cAOW,aAAA,GAAuB,GAAA,cAAe,OAAA;;;;;;;cAgBtC,YAAA,GACX,OAAA,GAAU,mBAAA,KACT,OAAA;EAAU,SAAA;EAAmB,YAAA;AAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/engine",
3
- "version": "9.0.0-canary.15",
3
+ "version": "9.0.0-canary.17",
4
4
  "private": false,
5
5
  "description": "Scans and builds Intlayer declaration files into dictionaries based on Intlayer configuration.",
6
6
  "keywords": [
@@ -142,13 +142,13 @@
142
142
  },
143
143
  "dependencies": {
144
144
  "@babel/parser": "7.29.7",
145
- "@intlayer/api": "9.0.0-canary.15",
146
- "@intlayer/config": "9.0.0-canary.15",
147
- "@intlayer/core": "9.0.0-canary.15",
148
- "@intlayer/dictionaries-entry": "9.0.0-canary.15",
149
- "@intlayer/remote-dictionaries-entry": "9.0.0-canary.15",
150
- "@intlayer/types": "9.0.0-canary.15",
151
- "@intlayer/unmerged-dictionaries-entry": "9.0.0-canary.15",
145
+ "@intlayer/api": "9.0.0-canary.17",
146
+ "@intlayer/config": "9.0.0-canary.17",
147
+ "@intlayer/core": "9.0.0-canary.17",
148
+ "@intlayer/dictionaries-entry": "9.0.0-canary.17",
149
+ "@intlayer/remote-dictionaries-entry": "9.0.0-canary.17",
150
+ "@intlayer/types": "9.0.0-canary.17",
151
+ "@intlayer/unmerged-dictionaries-entry": "9.0.0-canary.17",
152
152
  "@parcel/watcher": "2.5.6",
153
153
  "defu": "6.1.7",
154
154
  "fast-glob": "3.3.3",
@@ -164,7 +164,7 @@
164
164
  "rimraf": "6.1.3",
165
165
  "tsdown": "0.21.10",
166
166
  "typescript": "6.0.3",
167
- "vitest": "4.1.9",
167
+ "vitest": "4.1.10",
168
168
  "zod": "4.4.3"
169
169
  },
170
170
  "engines": {