Conversation
📝 WalkthroughWalkthroughMigrates vNext into a unified engineId model and switches SDK/CLI to api.lingo.dev: endpoints now use /process/* and /users/me, authentication uses X-API-Key, vNext code paths removed, and config v1.15 adds engineId with auto-migration from vNext. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI (run/i18n/ci)
participant Localizer as Localizer/Processor
participant API as api.lingo.dev
CLI->>Localizer: createLocalizer(provider, engineId?, apiKey)
CLI->>Localizer: localize(request with filePath, triggerType, sessionId)
Localizer->>API: POST /process/localize\nHeaders: X-API-Key: <apiKey>\nBody includes engineId?
API-->>Localizer: 200 OK (localized data)
Localizer-->>CLI: processed result
CLI->>API: GET /users/me\nHeaders: X-API-Key: <apiKey>
API-->>CLI: 200 OK (identity)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
packages/new-compiler/src/utils/observability.ts (1)
103-115: Consider deduplicatingtryGetEmailacross compiler packages.This request block is now duplicated with
packages/compiler/src/utils/observability.ts; extracting a shared helper would reduce future drift and avoid split fixes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/new-compiler/src/utils/observability.ts` around lines 103 - 115, Extract the duplicated HTTP user lookup into a shared helper and replace both copies of tryGetEmail with it: create a new exported function (e.g., fetchUserEmail or getUserEmailFromApi) that accepts apiUrl and apiKey, performs the fetch to `${apiUrl}/users/me` with the same headers and error handling, and returns the email or null; then update the existing tryGetEmail implementations to call this shared helper (importing it) and remove the duplicated fetch logic from both tryGetEmail functions so future changes are centralized.packages/cli/src/cli/cmd/ci/index.ts (1)
90-92: Update missing-key guidance to includeLINGO_API_KEY.Line 91 currently suggests only
LINGODOTDEV_API_KEY, but settings now acceptLINGO_API_KEYas well.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/cli/cmd/ci/index.ts` around lines 90 - 92, Update the error message emitted by the console.error call in the CI command (the console.error in packages/cli/src/cli/cmd/ci/index.ts) to mention both accepted environment variable names ("LINGODOTDEV_API_KEY" and "LINGO_API_KEY") along with the existing guidance to use the --api-key flag; modify the string so it clearly lists both env vars and the flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/cli/src/cli/cmd/ci/index.ts`:
- Around line 89-94: The auth failure currently just logs and returns (see the
check for settings.auth.apiKey and the other early returns), which exits with
code 0; change these early-return branches to terminate with a non-zero exit
code (e.g., call process.exit(1) or throw an error) so CI detects failure—update
the blocks that log via console.error and then return to instead log the error
and immediately call process.exit(1) (or throw) to fail the process.
In `@packages/cli/src/cli/cmd/run/setup.ts`:
- Around line 89-92: The current task's enabled predicate and execution call
assume ctx.localizer.validateSettings exists, which causes a runtime crash for
the "pseudo" localizer; in the async task (task: async (ctx, task) => { ... })
guard the call to ctx.localizer!.validateSettings by checking that ctx.localizer
is present and typeof ctx.localizer.validateSettings === "function" before
invoking it, and treat missing validateSettings as valid (or handle
appropriately) so the validationStatus access and .valid check cannot throw;
update both the enabled/decision logic and the call site to use this predicate
around validateSettings to avoid calling an undefined function.
In `@packages/cli/src/cli/utils/settings.ts`:
- Line 23: The deprecation warning logic needs to treat LINGO_API_KEY as a
migrated key so users with LINGO_API_KEY set (but still having REPLEXICA_API_KEY
present) don't get a false legacy warning; update the deprecation/legacy check
that currently examines env and REPLEXICA_API_KEY to also consider
env.LINGO_API_KEY (and any related conditional that uses env.LINGO_API_KEY ||
...) so the warning is suppressed when LINGO_API_KEY is present, ensuring the
logic that emits the legacy warning (the deprecation check/legacy warning branch
in settings.ts) accounts for the new key.
In `@packages/spec/src/config.ts`:
- Around line 610-624: The schema for v1.15 currently allows legacy vNext fields
so extendConfigDefinition.parse's schema.safeParse succeeds and skips
createUpgrader; update createSchema to explicitly reject vNext (e.g., include
vNext: Z.any().optional().refine(() => false) or mark it as Z.never()) so
configs containing vNext fail validation and are passed into createUpgrader,
ensuring createUpgrader logic (which maps vNext → engineId) runs; modify the
createSchema entry (the createSchema function and its returned object) to
explicitly forbid vNext while keeping engineId optional.
---
Nitpick comments:
In `@packages/cli/src/cli/cmd/ci/index.ts`:
- Around line 90-92: Update the error message emitted by the console.error call
in the CI command (the console.error in packages/cli/src/cli/cmd/ci/index.ts) to
mention both accepted environment variable names ("LINGODOTDEV_API_KEY" and
"LINGO_API_KEY") along with the existing guidance to use the --api-key flag;
modify the string so it clearly lists both env vars and the flag.
In `@packages/new-compiler/src/utils/observability.ts`:
- Around line 103-115: Extract the duplicated HTTP user lookup into a shared
helper and replace both copies of tryGetEmail with it: create a new exported
function (e.g., fetchUserEmail or getUserEmailFromApi) that accepts apiUrl and
apiKey, performs the fetch to `${apiUrl}/users/me` with the same headers and
error handling, and returns the email or null; then update the existing
tryGetEmail implementations to call this shared helper (importing it) and remove
the duplicated fetch logic from both tryGetEmail functions so future changes are
centralized.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bc024c29-d9e1-47cd-b6f3-83c06168ccd8
📒 Files selected for processing (20)
.changeset/thirty-pots-judge.mdpackages/cli/src/cli/cmd/ci/index.tspackages/cli/src/cli/cmd/i18n.tspackages/cli/src/cli/cmd/run/setup.tspackages/cli/src/cli/localizer/_types.tspackages/cli/src/cli/localizer/index.tspackages/cli/src/cli/localizer/lingodotdev-vnext.tspackages/cli/src/cli/localizer/lingodotdev.tspackages/cli/src/cli/processor/index.tspackages/cli/src/cli/processor/lingo.tspackages/cli/src/cli/utils/auth.tspackages/cli/src/cli/utils/settings.tspackages/compiler/src/utils/observability.tspackages/new-compiler/src/utils/observability.tspackages/sdk/src/abort-controller.specs.tspackages/sdk/src/index.spec.tspackages/sdk/src/index.tspackages/sdk/src/utils/observability.spec.tspackages/sdk/src/utils/observability.tspackages/spec/src/config.ts
💤 Files with no reviewable changes (1)
- packages/cli/src/cli/localizer/lingodotdev-vnext.ts
| if (!settings.auth.apiKey) { | ||
| console.error( | ||
| "No API key provided. Set LINGODOTDEV_API_KEY environment variable or use --api-key flag.", | ||
| ); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Auth failures should fail CI with non-zero exit code.
At Line 93 and Line 104, early return exits successfully. CI can pass even when authentication is missing/invalid.
🛠️ Proposed fix
if (!settings.auth.apiKey) {
console.error(
"No API key provided. Set LINGODOTDEV_API_KEY environment variable or use --api-key flag.",
);
+ process.exitCode = 1;
return;
}
@@
const auth = await authenticator.whoami();
if (!auth) {
console.error("Not authenticated");
+ process.exitCode = 1;
return;
}Also applies to: 101-105
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/cli/src/cli/cmd/ci/index.ts` around lines 89 - 94, The auth failure
currently just logs and returns (see the check for settings.auth.apiKey and the
other early returns), which exits with code 0; change these early-return
branches to terminate with a non-zero exit code (e.g., call process.exit(1) or
throw an error) so CI detects failure—update the blocks that log via
console.error and then return to instead log the error and immediately call
process.exit(1) (or throw) to fail the process.
| enabled: (ctx) => ctx.localizer?.id !== "Lingo.dev", | ||
| task: async (ctx, task) => { | ||
| const validationStatus = await ctx.localizer!.validateSettings!(); | ||
| if (!validationStatus.valid) { |
There was a problem hiding this comment.
Pseudo mode can crash in configuration validation.
At Line 89, the task is enabled for "pseudo", but pseudo localizer does not implement validateSettings, so Line 91 can throw at runtime.
🧩 Proposed fix
{
title: "Validating configuration",
- enabled: (ctx) => ctx.localizer?.id !== "Lingo.dev",
+ enabled: (ctx) =>
+ ctx.localizer?.id !== "Lingo.dev" &&
+ ctx.localizer?.id !== "pseudo" &&
+ !!ctx.localizer?.validateSettings,
task: async (ctx, task) => {
const validationStatus = await ctx.localizer!.validateSettings!();
if (!validationStatus.valid) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| enabled: (ctx) => ctx.localizer?.id !== "Lingo.dev", | |
| task: async (ctx, task) => { | |
| const validationStatus = await ctx.localizer!.validateSettings!(); | |
| if (!validationStatus.valid) { | |
| enabled: (ctx) => | |
| ctx.localizer?.id !== "Lingo.dev" && | |
| ctx.localizer?.id !== "pseudo" && | |
| !!ctx.localizer?.validateSettings, | |
| task: async (ctx, task) => { | |
| const validationStatus = await ctx.localizer!.validateSettings!(); | |
| if (!validationStatus.valid) { |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/cli/src/cli/cmd/run/setup.ts` around lines 89 - 92, The current
task's enabled predicate and execution call assume
ctx.localizer.validateSettings exists, which causes a runtime crash for the
"pseudo" localizer; in the async task (task: async (ctx, task) => { ... }) guard
the call to ctx.localizer!.validateSettings by checking that ctx.localizer is
present and typeof ctx.localizer.validateSettings === "function" before invoking
it, and treat missing validateSettings as valid (or handle appropriately) so the
validationStatus access and .valid check cannot throw; update both the
enabled/decision logic and the call site to use this predicate around
validateSettings to avoid calling an undefined function.
| createSchema: (baseSchema) => | ||
| baseSchema.extend({ | ||
| engineId: Z.string().optional(), | ||
| }), | ||
| createDefaultValue: (baseDefaultValue) => ({ | ||
| ...baseDefaultValue, | ||
| version: "1.15", | ||
| }), | ||
| createUpgrader: (oldConfig) => { | ||
| const { vNext, ...rest } = oldConfig as any; | ||
| return { | ||
| ...rest, | ||
| version: "1.15", | ||
| ...(vNext && !rest.engineId ? { engineId: vNext } : {}), | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n -A 20 'extendConfigDefinition.*=.*\(' packages/spec/src/config.ts | head -80Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
rg -n -B 5 -A 15 'safeParse\(rawConfig\)' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 810
🏁 Script executed:
rg -n -B 5 -A 15 'const baseConfig = definition.parse' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 653
🏁 Script executed:
rg -n -B 2 -A 2 'configV1_15Definition' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 422
🏁 Script executed:
sed -n '605,627p' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 676
🏁 Script executed:
rg -n -B 5 -A 10 'configV1_14Definition' packages/spec/src/config.ts | tail -40Repository: lingodotdev/lingo.dev
Length of output: 1105
🏁 Script executed:
rg -n 'vNext' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 349
🏁 Script executed:
sed -n '490,510p' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 567
🏁 Script executed:
sed -n '500,580p' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 2314
🏁 Script executed:
rg -n -B 10 'createUpgrader:' packages/spec/src/config.ts | grep -A 10 'v1_12\|v1_13\|v1_14'Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
rg -n 'baseSchema.extend\|baseSchema.omit\|baseSchema.pick' packages/spec/src/config.ts | head -20Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
sed -n '55,95p' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 1234
🏁 Script executed:
rg -n 'const extendConfigDefinition' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 100
🏁 Script executed:
sed -n '48,95p' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 1521
🏁 Script executed:
rg -n 'vNext.*Z\.never\|baseSchema\.omit.*vNext' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
sed -n '587,605p' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 490
🏁 Script executed:
cat -n packages/spec/src/config.ts | sed -n '45,100p'Repository: lingodotdev/lingo.dev
Length of output: 2109
🏁 Script executed:
rg -n 'Z\.never' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Check if vNext was ever explicitly removed or rejected in schema chain
rg -n 'omit\|pick\|exclude' packages/spec/src/config.ts | grep -i 'vNext\|v1_'Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Check the complete schema inheritance chain more clearly
cat -n packages/spec/src/config.ts | sed -n '495,515p'Repository: lingodotdev/lingo.dev
Length of output: 709
🏁 Script executed:
# Look for test files that might validate this behavior
find . -name '*.test.ts' -o -name '*.spec.ts' | xargs grep -l 'vNext\|configV1_15\|engineId' 2>/dev/null | head -5Repository: lingodotdev/lingo.dev
Length of output: 97
🏁 Script executed:
# Check if there's any omit/pick pattern used anywhere to remove fields
rg -n '\.omit\(|\.pick\(' packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
cat packages/sdk/src/index.spec.ts | grep -A 20 -B 5 'vNext\|engineId' | head -60Repository: lingodotdev/lingo.dev
Length of output: 2035
🏁 Script executed:
# Verify the actual schema chain - does v1.14 keep vNext visible?
rg -n 'configV1_14Definition\|configV1_13Definition' packages/spec/src/config.ts -A 1 | head -20Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Check if the baseSchema in v1.15 truly carries vNext from prior versions
# by looking at what gets passed to createSchema
cat -n packages/spec/src/config.ts | sed -n '595,625p'Repository: lingodotdev/lingo.dev
Length of output: 1041
🏁 Script executed:
# Trace schema inheritance - check what baseSchema contains when it reaches v1.15
# Check if there's any test that validates the migration behavior
rg -n 'vNext.*engineId\|migration\|upgrade' packages/sdk/src/index.spec.ts -iRepository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Verify behavior: does a config with vNext pass v1.15 schema validation?
# Look for any test files in the spec package
find packages/spec -name '*.test.ts' -o -name '*.spec.ts' 2>/dev/nullRepository: lingodotdev/lingo.dev
Length of output: 163
🏁 Script executed:
# Get file size to understand scope
wc -l packages/spec/src/config.tsRepository: lingodotdev/lingo.dev
Length of output: 96
🏁 Script executed:
# Check config tests for migration behavior
rg -n 'vNext\|engineId\|v1_15' packages/spec/src/config.spec.ts -B 3 -A 10Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Check if there's test about schema validation or migration
cat packages/spec/src/config.spec.ts | head -100Repository: lingodotdev/lingo.dev
Length of output: 2412
🏁 Script executed:
# Search the entire config.spec.ts for vNext or engineId
grep -n 'vNext\|engineId' packages/spec/src/config.spec.tsRepository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Get the rest of the config.spec.ts file
wc -l packages/spec/src/config.spec.tsRepository: lingodotdev/lingo.dev
Length of output: 101
🏁 Script executed:
# Check if there are any integration tests or e2e tests
find . -type f \( -name '*.test.ts' -o -name '*.spec.ts' \) | xargs grep -l 'v1_15\|vNext.*engineId' 2>/dev/null | head -10Repository: lingodotdev/lingo.dev
Length of output: 47
🏁 Script executed:
# Let me verify the exact logic one more time by checking the full extendConfigDefinition implementation
cat -n packages/spec/src/config.ts | sed -n '45,95p'Repository: lingodotdev/lingo.dev
Length of output: 1965
🏁 Script executed:
# Check what happens with baseSchema.extend - does it preserve parent fields?
# Try a simple test to understand Zod behavior
python3 << 'EOF'
# Simulating Zod extend behavior
# When you call baseSchema.extend({newField: ...})
# It preserves all parent schema fields AND adds new ones
# It does NOT automatically reject parent fields
# So v1.15's baseSchema (from v1.14) contains vNext (inherited from v1.11)
# When v1.15 extends with {engineId: ...}, vNext is still there and optional
# This means a config with vNext will pass validation
print("Schema inheritance chain:")
print("v1.11: adds vNext as optional")
print("v1.12, v1.13, v1.14: inherit vNext (no changes)")
print("v1.15: extends with engineId as optional")
print("")
print("Result: v1.15 schema accepts vNext (inherited)")
print("If config has vNext but no engineId: passes validation")
print("If validation passes: upgrader never runs")
print("If upgrader never runs: vNext->engineId migration skipped")
EOFRepository: lingodotdev/lingo.dev
Length of output: 412
vNext → engineId auto-migration skipped for configs that pass schema validation.
The extendConfigDefinition.parse function returns immediately when schema.safeParse(rawConfig) succeeds (line 62-63), preventing the upgrader from running. Since v1.15's schema inherits vNext from v1.11 and never explicitly rejects it, a config containing vNext will pass validation and bypass the migration logic entirely.
To force the migration: explicitly reject vNext in v1.15's schema so configs containing it fail validation and are routed through the upgrader.
🔧 Proposed fix
export const configV1_15Definition = extendConfigDefinition(
configV1_14Definition,
{
createSchema: (baseSchema) =>
baseSchema.extend({
engineId: Z.string().optional(),
+ vNext: Z.never(),
}),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| createSchema: (baseSchema) => | |
| baseSchema.extend({ | |
| engineId: Z.string().optional(), | |
| }), | |
| createDefaultValue: (baseDefaultValue) => ({ | |
| ...baseDefaultValue, | |
| version: "1.15", | |
| }), | |
| createUpgrader: (oldConfig) => { | |
| const { vNext, ...rest } = oldConfig as any; | |
| return { | |
| ...rest, | |
| version: "1.15", | |
| ...(vNext && !rest.engineId ? { engineId: vNext } : {}), | |
| }; | |
| createSchema: (baseSchema) => | |
| baseSchema.extend({ | |
| engineId: Z.string().optional(), | |
| vNext: Z.never(), | |
| }), | |
| createDefaultValue: (baseDefaultValue) => ({ | |
| ...baseDefaultValue, | |
| version: "1.15", | |
| }), | |
| createUpgrader: (oldConfig) => { | |
| const { vNext, ...rest } = oldConfig as any; | |
| return { | |
| ...rest, | |
| version: "1.15", | |
| ...(vNext && !rest.engineId ? { engineId: vNext } : {}), | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/spec/src/config.ts` around lines 610 - 624, The schema for v1.15
currently allows legacy vNext fields so extendConfigDefinition.parse's
schema.safeParse succeeds and skips createUpgrader; update createSchema to
explicitly reject vNext (e.g., include vNext: Z.any().optional().refine(() =>
false) or mark it as Z.never()) so configs containing vNext fail validation and
are passed into createUpgrader, ensuring createUpgrader logic (which maps vNext
→ engineId) runs; modify the createSchema entry (the createSchema function and
its returned object) to explicitly forbid vNext while keeping engineId optional.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/cli/src/cli/utils/settings.ts (1)
204-209:⚠️ Potential issue | 🟡 MinorInfo message should also check
LINGO_API_KEY.The condition only checks
LINGODOTDEV_API_KEYbutLINGO_API_KEYis now the primary environment variable. Users settingLINGO_API_KEYwon't see the info message when it overridessystemFile.auth?.apiKey.🔧 Proposed fix
- if (env.LINGODOTDEV_API_KEY && systemFile.auth?.apiKey) { + if ((env.LINGO_API_KEY || env.LINGODOTDEV_API_KEY) && systemFile.auth?.apiKey) { console.info( "\x1b[36m%s\x1b[0m", - `ℹ️ Using LINGODOTDEV_API_KEY env var instead of credentials from user config`, + `ℹ️ Using ${env.LINGO_API_KEY ? 'LINGO_API_KEY' : 'LINGODOTDEV_API_KEY'} env var instead of credentials from user config`, ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/cli/utils/settings.ts` around lines 204 - 209, Update the conditional that currently checks env.LINGODOTDEV_API_KEY when deciding to log the info about using an env var over systemFile.auth?.apiKey so it also checks env.LINGO_API_KEY (the new primary env var); specifically modify the condition that references env.LINGODOTDEV_API_KEY and the info log text (in the same block that inspects systemFile.auth?.apiKey) to account for either environment variable being present so users who set LINGO_API_KEY see the same message.
♻️ Duplicate comments (1)
packages/cli/src/cli/cmd/ci/index.ts (1)
75-91:⚠️ Potential issue | 🔴 CriticalAuth failures should fail CI with non-zero exit code.
Both early
returnstatements (Lines 79 and 90) exit successfully with code 0. CI pipelines will incorrectly pass when authentication is missing or invalid.🛠️ Proposed fix
if (!settings.auth.apiKey) { console.error( "No API key provided. Set LINGO_API_KEY environment variable or use --api-key flag.", ); + process.exitCode = 1; return; } const authenticator = createAuthenticator({ apiUrl: settings.auth.apiUrl, apiKey: settings.auth.apiKey, }); const auth = await authenticator.whoami(); if (!auth) { console.error("Not authenticated"); + process.exitCode = 1; return; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/cli/cmd/ci/index.ts` around lines 75 - 91, The CI command currently returns early on auth failures which yields exit code 0; in the auth checks around settings.auth.apiKey and after awaiting authenticator.whoami(), replace the plain returns with a non-zero process exit (e.g., call process.exit(1)) after logging the error so the process fails the CI build; locate the logic that constructs the authenticator via createAuthenticator and the auth check using authenticator.whoami() to apply this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/cli/src/cli/utils/init-ci-cd.ts`:
- Line 108: The workflow template currently hard-codes the secret line "api-key:
${{ secrets.LINGO_API_KEY }}", which will break repos that still use a different
secret name; change the writer in init-ci-cd so it preserves existing secret
names or prompts a clear migration warning before overwriting workflows: detect
if a workflow file already exists and either (a) keep its existing secret key
entry instead of replacing it with "secrets.LINGO_API_KEY", or (b) if you must
replace it, emit an explicit interactive/CLI migration warning and require
confirmation; update the code path that emits the template (the code that writes
the "api-key: ${{ secrets.LINGO_API_KEY }}" line) to implement this
preserve-or-warn behavior.
---
Outside diff comments:
In `@packages/cli/src/cli/utils/settings.ts`:
- Around line 204-209: Update the conditional that currently checks
env.LINGODOTDEV_API_KEY when deciding to log the info about using an env var
over systemFile.auth?.apiKey so it also checks env.LINGO_API_KEY (the new
primary env var); specifically modify the condition that references
env.LINGODOTDEV_API_KEY and the info log text (in the same block that inspects
systemFile.auth?.apiKey) to account for either environment variable being
present so users who set LINGO_API_KEY see the same message.
---
Duplicate comments:
In `@packages/cli/src/cli/cmd/ci/index.ts`:
- Around line 75-91: The CI command currently returns early on auth failures
which yields exit code 0; in the auth checks around settings.auth.apiKey and
after awaiting authenticator.whoami(), replace the plain returns with a non-zero
process exit (e.g., call process.exit(1)) after logging the error so the process
fails the CI build; locate the logic that constructs the authenticator via
createAuthenticator and the auth check using authenticator.whoami() to apply
this change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 89f44a17-435e-4701-a359-2c30ba7dfcfa
📒 Files selected for processing (6)
packages/cli/src/cli/cmd/ci/index.tspackages/cli/src/cli/cmd/ci/platforms/_base.tspackages/cli/src/cli/cmd/login.tspackages/cli/src/cli/localizer/lingodotdev.tspackages/cli/src/cli/utils/init-ci-cd.tspackages/cli/src/cli/utils/settings.ts
| - uses: lingodotdev/lingo.dev@main | ||
| with: | ||
| api-key: \${{ secrets.LINGODOTDEV_API_KEY }} | ||
| api-key: \${{ secrets.LINGO_API_KEY }} |
There was a problem hiding this comment.
Avoid breaking existing GitHub CI secrets on overwrite.
Line 108 now hard-codes secrets.LINGO_API_KEY. If an existing repo re-runs init-ci-cd and accepts overwrite, the next workflow run will fail unless the maintainer has already renamed the repository secret. Please keep the scaffold backward-compatible here, or emit an explicit migration warning before writing the file.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/cli/src/cli/utils/init-ci-cd.ts` at line 108, The workflow template
currently hard-codes the secret line "api-key: ${{ secrets.LINGO_API_KEY }}",
which will break repos that still use a different secret name; change the writer
in init-ci-cd so it preserves existing secret names or prompts a clear migration
warning before overwriting workflows: detect if a workflow file already exists
and either (a) keep its existing secret key entry instead of replacing it with
"secrets.LINGO_API_KEY", or (b) if you must replace it, emit an explicit
interactive/CLI migration warning and require confirmation; update the code path
that emits the template (the code that writes the "api-key: ${{
secrets.LINGO_API_KEY }}" line) to implement this preserve-or-warn behavior.
Summary
Unify CLI and SDK to a single API auth path using
X-API-Keyheader, moveengineIdfrom URL path to request body, and remove the legacy vNext/non-vNext split.Changes
X-API-Keyheader (removedAuthorization: Bearerpath);engineIdis now an optional body parameter instead of a URL path segment; URL is always/process/localizelingodotdev-vnext.tslocalizer intolingodotdev.ts; removedisVNextbranching in CI flowengineIdfield; auto-migratesvNext→engineIdon config loadGET /users/mewithX-API-Key(wasPOST /whoamiwithAuthorization: Bearerin legacy path)X-API-Key+GET /users/me; fixedContent-Typeheader typoTesting
Business logic tests added:
engineIdincluded in request body when providedengineIdabsent from body when not configuredGET /users/mewithX-API-KeyVisuals
N/A — no UI changes.
Checklist
Summary by CodeRabbit
New Features
Chores
Tests