lingo.dev 0.117.16 → 0.117.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.
- package/build/cli.cjs +156 -55
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +146 -45
- package/build/cli.mjs.map +1 -1
- package/package.json +3 -3
package/build/cli.mjs
CHANGED
|
@@ -10798,27 +10798,128 @@ function withExponentialBackoff(fn, maxAttempts = 3, baseDelay = 1e3) {
|
|
|
10798
10798
|
// src/cli/utils/observability.ts
|
|
10799
10799
|
import pkg from "node-machine-id";
|
|
10800
10800
|
import https from "https";
|
|
10801
|
+
|
|
10802
|
+
// src/cli/utils/repository-id.ts
|
|
10803
|
+
import { execSync } from "child_process";
|
|
10804
|
+
var cachedGitRepoId = void 0;
|
|
10805
|
+
function getRepositoryId() {
|
|
10806
|
+
const ciRepoId = getCIRepositoryId();
|
|
10807
|
+
if (ciRepoId) return ciRepoId;
|
|
10808
|
+
const gitRepoId = getGitRepositoryId();
|
|
10809
|
+
if (gitRepoId) return gitRepoId;
|
|
10810
|
+
return null;
|
|
10811
|
+
}
|
|
10812
|
+
function getCIRepositoryId() {
|
|
10813
|
+
if (process.env.GITHUB_REPOSITORY) {
|
|
10814
|
+
return `github:${process.env.GITHUB_REPOSITORY}`;
|
|
10815
|
+
}
|
|
10816
|
+
if (process.env.CI_PROJECT_PATH) {
|
|
10817
|
+
return `gitlab:${process.env.CI_PROJECT_PATH}`;
|
|
10818
|
+
}
|
|
10819
|
+
if (process.env.BITBUCKET_REPO_FULL_NAME) {
|
|
10820
|
+
return `bitbucket:${process.env.BITBUCKET_REPO_FULL_NAME}`;
|
|
10821
|
+
}
|
|
10822
|
+
return null;
|
|
10823
|
+
}
|
|
10824
|
+
function getGitRepositoryId() {
|
|
10825
|
+
if (cachedGitRepoId !== void 0) {
|
|
10826
|
+
return cachedGitRepoId;
|
|
10827
|
+
}
|
|
10828
|
+
try {
|
|
10829
|
+
const remoteUrl = execSync("git config --get remote.origin.url", {
|
|
10830
|
+
encoding: "utf8",
|
|
10831
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
10832
|
+
}).trim();
|
|
10833
|
+
if (!remoteUrl) {
|
|
10834
|
+
cachedGitRepoId = null;
|
|
10835
|
+
return null;
|
|
10836
|
+
}
|
|
10837
|
+
cachedGitRepoId = parseGitUrl(remoteUrl);
|
|
10838
|
+
return cachedGitRepoId;
|
|
10839
|
+
} catch {
|
|
10840
|
+
cachedGitRepoId = null;
|
|
10841
|
+
return null;
|
|
10842
|
+
}
|
|
10843
|
+
}
|
|
10844
|
+
function parseGitUrl(url) {
|
|
10845
|
+
const cleanUrl = url.replace(/\.git$/, "");
|
|
10846
|
+
let platform = null;
|
|
10847
|
+
if (cleanUrl.includes("github.com")) {
|
|
10848
|
+
platform = "github";
|
|
10849
|
+
} else if (cleanUrl.includes("gitlab.com")) {
|
|
10850
|
+
platform = "gitlab";
|
|
10851
|
+
} else if (cleanUrl.includes("bitbucket.org")) {
|
|
10852
|
+
platform = "bitbucket";
|
|
10853
|
+
}
|
|
10854
|
+
const sshMatch = cleanUrl.match(/[@:]([^:/@]+\/[^:/@]+)$/);
|
|
10855
|
+
const httpsMatch = cleanUrl.match(/\/([^/]+\/[^/]+)$/);
|
|
10856
|
+
const repoPath = sshMatch?.[1] || httpsMatch?.[1];
|
|
10857
|
+
if (!repoPath) return null;
|
|
10858
|
+
if (platform) {
|
|
10859
|
+
return `${platform}:${repoPath}`;
|
|
10860
|
+
}
|
|
10861
|
+
return `git:${repoPath}`;
|
|
10862
|
+
}
|
|
10863
|
+
|
|
10864
|
+
// src/cli/utils/observability.ts
|
|
10801
10865
|
var { machineIdSync } = pkg;
|
|
10802
10866
|
var POSTHOG_API_KEY = "phc_eR0iSoQufBxNY36k0f0T15UvHJdTfHlh8rJcxsfhfXk";
|
|
10803
10867
|
var POSTHOG_HOST = "eu.i.posthog.com";
|
|
10804
10868
|
var POSTHOG_PATH = "/i/v0/e/";
|
|
10805
10869
|
var REQUEST_TIMEOUT_MS = 1e3;
|
|
10870
|
+
var TRACKING_VERSION = "2.0";
|
|
10871
|
+
function determineDistinctId(providedId) {
|
|
10872
|
+
if (providedId) {
|
|
10873
|
+
const projectId = getRepositoryId();
|
|
10874
|
+
return {
|
|
10875
|
+
distinct_id: providedId,
|
|
10876
|
+
distinct_id_source: "email",
|
|
10877
|
+
project_id: projectId
|
|
10878
|
+
};
|
|
10879
|
+
}
|
|
10880
|
+
const repoId = getRepositoryId();
|
|
10881
|
+
if (repoId) {
|
|
10882
|
+
return {
|
|
10883
|
+
distinct_id: repoId,
|
|
10884
|
+
distinct_id_source: "git_repo",
|
|
10885
|
+
project_id: repoId
|
|
10886
|
+
};
|
|
10887
|
+
}
|
|
10888
|
+
const deviceId = `device-${machineIdSync()}`;
|
|
10889
|
+
if (process.env.DEBUG === "true") {
|
|
10890
|
+
console.warn(
|
|
10891
|
+
"[Tracking] Using device ID fallback. Consider using git repository for consistent tracking."
|
|
10892
|
+
);
|
|
10893
|
+
}
|
|
10894
|
+
return {
|
|
10895
|
+
distinct_id: deviceId,
|
|
10896
|
+
distinct_id_source: "device",
|
|
10897
|
+
project_id: null
|
|
10898
|
+
};
|
|
10899
|
+
}
|
|
10806
10900
|
function trackEvent(distinctId, event, properties) {
|
|
10807
10901
|
if (process.env.DO_NOT_TRACK === "1") {
|
|
10808
10902
|
return;
|
|
10809
10903
|
}
|
|
10810
10904
|
setImmediate(() => {
|
|
10811
10905
|
try {
|
|
10812
|
-
const
|
|
10906
|
+
const identityInfo = determineDistinctId(distinctId);
|
|
10907
|
+
if (process.env.DEBUG === "true") {
|
|
10908
|
+
console.log(
|
|
10909
|
+
`[Tracking] Event: ${event}, ID: ${identityInfo.distinct_id}, Source: ${identityInfo.distinct_id_source}`
|
|
10910
|
+
);
|
|
10911
|
+
}
|
|
10813
10912
|
const eventData = {
|
|
10814
10913
|
api_key: POSTHOG_API_KEY,
|
|
10815
10914
|
event,
|
|
10816
|
-
distinct_id:
|
|
10915
|
+
distinct_id: identityInfo.distinct_id,
|
|
10817
10916
|
properties: {
|
|
10818
10917
|
...properties,
|
|
10819
10918
|
$lib: "lingo.dev-cli",
|
|
10820
10919
|
$lib_version: process.env.npm_package_version || "unknown",
|
|
10821
|
-
|
|
10920
|
+
tracking_version: TRACKING_VERSION,
|
|
10921
|
+
distinct_id_source: identityInfo.distinct_id_source,
|
|
10922
|
+
project_id: identityInfo.project_id,
|
|
10822
10923
|
node_version: process.version,
|
|
10823
10924
|
is_ci: !!process.env.CI,
|
|
10824
10925
|
debug_enabled: process.env.DEBUG === "true"
|
|
@@ -11028,7 +11129,7 @@ var i18n_default = new Command14().command("i18n").description(
|
|
|
11028
11129
|
try {
|
|
11029
11130
|
flags = parseFlags(options);
|
|
11030
11131
|
} catch (parseError) {
|
|
11031
|
-
await trackEvent(
|
|
11132
|
+
await trackEvent(null, "cmd.i18n.error", {
|
|
11032
11133
|
errorType: "validation_error",
|
|
11033
11134
|
errorName: parseError.name || "ValidationError",
|
|
11034
11135
|
errorMessage: parseError.message || "Invalid command line options",
|
|
@@ -11428,7 +11529,7 @@ var i18n_default = new Command14().command("i18n").description(
|
|
|
11428
11529
|
});
|
|
11429
11530
|
} else {
|
|
11430
11531
|
ora.warn("Localization completed with errors.");
|
|
11431
|
-
await trackEvent(authId
|
|
11532
|
+
await trackEvent(authId, "cmd.i18n.error", {
|
|
11432
11533
|
flags,
|
|
11433
11534
|
...aggregateErrorAnalytics(
|
|
11434
11535
|
errorDetails,
|
|
@@ -11454,7 +11555,7 @@ var i18n_default = new Command14().command("i18n").description(
|
|
|
11454
11555
|
bucket: error.bucket
|
|
11455
11556
|
};
|
|
11456
11557
|
}
|
|
11457
|
-
await trackEvent(authId
|
|
11558
|
+
await trackEvent(authId, "cmd.i18n.error", {
|
|
11458
11559
|
flags,
|
|
11459
11560
|
errorType,
|
|
11460
11561
|
errorName: error.name || "Error",
|
|
@@ -11974,10 +12075,10 @@ import { Command as Command19 } from "interactive-commander";
|
|
|
11974
12075
|
import createOra from "ora";
|
|
11975
12076
|
|
|
11976
12077
|
// src/cli/cmd/ci/flows/pull-request.ts
|
|
11977
|
-
import { execSync as
|
|
12078
|
+
import { execSync as execSync3 } from "child_process";
|
|
11978
12079
|
|
|
11979
12080
|
// src/cli/cmd/ci/flows/in-branch.ts
|
|
11980
|
-
import { execSync } from "child_process";
|
|
12081
|
+
import { execSync as execSync2 } from "child_process";
|
|
11981
12082
|
import path18 from "path";
|
|
11982
12083
|
|
|
11983
12084
|
// src/cli/cmd/ci/flows/_base.ts
|
|
@@ -13210,7 +13311,7 @@ var run_default = new Command18().command("run").description("Run localization p
|
|
|
13210
13311
|
flags: ctx.flags
|
|
13211
13312
|
});
|
|
13212
13313
|
} catch (error) {
|
|
13213
|
-
await trackEvent(authId
|
|
13314
|
+
await trackEvent(authId, "cmd.run.error", {});
|
|
13214
13315
|
if (args.sound) {
|
|
13215
13316
|
await playSound("failure");
|
|
13216
13317
|
}
|
|
@@ -13230,15 +13331,15 @@ var InBranchFlow = class extends IntegrationFlow {
|
|
|
13230
13331
|
this.ora.start("Running Lingo.dev");
|
|
13231
13332
|
await this.runLingoDotDev(options.parallel);
|
|
13232
13333
|
this.ora.succeed("Done running Lingo.dev");
|
|
13233
|
-
|
|
13334
|
+
execSync2(`rm -f i18n.cache`, { stdio: "inherit" });
|
|
13234
13335
|
this.ora.start("Checking for changes");
|
|
13235
13336
|
const hasChanges = this.checkCommitableChanges();
|
|
13236
13337
|
this.ora.succeed(hasChanges ? "Changes detected" : "No changes detected");
|
|
13237
13338
|
if (hasChanges) {
|
|
13238
13339
|
this.ora.start("Committing changes");
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13340
|
+
execSync2(`git add .`, { stdio: "inherit" });
|
|
13341
|
+
execSync2(`git status --porcelain`, { stdio: "inherit" });
|
|
13342
|
+
execSync2(
|
|
13242
13343
|
`git commit -m ${escapeShellArg(
|
|
13243
13344
|
this.platformKit.config.commitMessage
|
|
13244
13345
|
)} --no-verify`,
|
|
@@ -13249,7 +13350,7 @@ var InBranchFlow = class extends IntegrationFlow {
|
|
|
13249
13350
|
this.ora.succeed("Changes committed");
|
|
13250
13351
|
this.ora.start("Pushing changes to remote");
|
|
13251
13352
|
const currentBranch = this.i18nBranchName ?? this.platformKit.platformConfig.baseBranchName;
|
|
13252
|
-
|
|
13353
|
+
execSync2(
|
|
13253
13354
|
`git push origin ${currentBranch} ${options.force ? "--force" : ""}`,
|
|
13254
13355
|
{
|
|
13255
13356
|
stdio: "inherit"
|
|
@@ -13260,7 +13361,7 @@ var InBranchFlow = class extends IntegrationFlow {
|
|
|
13260
13361
|
return hasChanges;
|
|
13261
13362
|
}
|
|
13262
13363
|
checkCommitableChanges() {
|
|
13263
|
-
return
|
|
13364
|
+
return execSync2('git status --porcelain || echo "has_changes"', {
|
|
13264
13365
|
encoding: "utf8"
|
|
13265
13366
|
}).length > 0;
|
|
13266
13367
|
}
|
|
@@ -13285,17 +13386,17 @@ var InBranchFlow = class extends IntegrationFlow {
|
|
|
13285
13386
|
const { baseBranchName } = this.platformKit.platformConfig;
|
|
13286
13387
|
const gitConfig = getGitConfig(this.platformKit);
|
|
13287
13388
|
this.ora.info(`Current working directory:`);
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13389
|
+
execSync2(`pwd`, { stdio: "inherit" });
|
|
13390
|
+
execSync2(`ls -la`, { stdio: "inherit" });
|
|
13391
|
+
execSync2(`git config --global safe.directory ${process.cwd()}`);
|
|
13392
|
+
execSync2(`git config user.name "${gitConfig.userName}"`);
|
|
13393
|
+
execSync2(`git config user.email "${gitConfig.userEmail}"`);
|
|
13293
13394
|
this.platformKit?.gitConfig();
|
|
13294
|
-
|
|
13295
|
-
|
|
13395
|
+
execSync2(`git fetch origin ${baseBranchName}`, { stdio: "inherit" });
|
|
13396
|
+
execSync2(`git checkout ${baseBranchName} --`, { stdio: "inherit" });
|
|
13296
13397
|
if (!processOwnCommits) {
|
|
13297
13398
|
const currentAuthor = `${gitConfig.userName} <${gitConfig.userEmail}>`;
|
|
13298
|
-
const authorOfLastCommit =
|
|
13399
|
+
const authorOfLastCommit = execSync2(
|
|
13299
13400
|
`git log -1 --pretty=format:'%an <%ae>'`
|
|
13300
13401
|
).toString();
|
|
13301
13402
|
if (authorOfLastCommit === currentAuthor) {
|
|
@@ -13399,18 +13500,18 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
13399
13500
|
return prNumber;
|
|
13400
13501
|
}
|
|
13401
13502
|
checkoutI18nBranch(i18nBranchName) {
|
|
13402
|
-
|
|
13403
|
-
|
|
13503
|
+
execSync3(`git fetch origin ${i18nBranchName}`, { stdio: "inherit" });
|
|
13504
|
+
execSync3(`git checkout -b ${i18nBranchName}`, {
|
|
13404
13505
|
stdio: "inherit"
|
|
13405
13506
|
});
|
|
13406
13507
|
}
|
|
13407
13508
|
createI18nBranch(i18nBranchName) {
|
|
13408
13509
|
try {
|
|
13409
|
-
|
|
13510
|
+
execSync3(
|
|
13410
13511
|
`git fetch origin ${this.platformKit.platformConfig.baseBranchName}`,
|
|
13411
13512
|
{ stdio: "inherit" }
|
|
13412
13513
|
);
|
|
13413
|
-
|
|
13514
|
+
execSync3(
|
|
13414
13515
|
`git checkout -b ${i18nBranchName} origin/${this.platformKit.platformConfig.baseBranchName}`,
|
|
13415
13516
|
{
|
|
13416
13517
|
stdio: "inherit"
|
|
@@ -13435,7 +13536,7 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
13435
13536
|
this.ora.start(
|
|
13436
13537
|
`Fetching latest changes from ${this.platformKit.platformConfig.baseBranchName}`
|
|
13437
13538
|
);
|
|
13438
|
-
|
|
13539
|
+
execSync3(
|
|
13439
13540
|
`git fetch origin ${this.platformKit.platformConfig.baseBranchName}`,
|
|
13440
13541
|
{ stdio: "inherit" }
|
|
13441
13542
|
);
|
|
@@ -13444,7 +13545,7 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
13444
13545
|
);
|
|
13445
13546
|
try {
|
|
13446
13547
|
this.ora.start("Attempting to rebase branch");
|
|
13447
|
-
|
|
13548
|
+
execSync3(
|
|
13448
13549
|
`git rebase origin/${this.platformKit.platformConfig.baseBranchName}`,
|
|
13449
13550
|
{ stdio: "inherit" }
|
|
13450
13551
|
);
|
|
@@ -13452,12 +13553,12 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
13452
13553
|
} catch (error) {
|
|
13453
13554
|
this.ora.warn("Rebase failed, falling back to alternative sync method");
|
|
13454
13555
|
this.ora.start("Aborting failed rebase");
|
|
13455
|
-
|
|
13556
|
+
execSync3("git rebase --abort", { stdio: "inherit" });
|
|
13456
13557
|
this.ora.succeed("Aborted failed rebase");
|
|
13457
13558
|
this.ora.start(
|
|
13458
13559
|
`Resetting to ${this.platformKit.platformConfig.baseBranchName}`
|
|
13459
13560
|
);
|
|
13460
|
-
|
|
13561
|
+
execSync3(
|
|
13461
13562
|
`git reset --hard origin/${this.platformKit.platformConfig.baseBranchName}`,
|
|
13462
13563
|
{ stdio: "inherit" }
|
|
13463
13564
|
);
|
|
@@ -13466,15 +13567,15 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
13466
13567
|
);
|
|
13467
13568
|
this.ora.start("Restoring target files");
|
|
13468
13569
|
const targetFiles = ["i18n.lock"];
|
|
13469
|
-
const targetFileNames =
|
|
13570
|
+
const targetFileNames = execSync3(
|
|
13470
13571
|
`npx lingo.dev@latest show files --target ${this.platformKit.platformConfig.baseBranchName}`,
|
|
13471
13572
|
{ encoding: "utf8" }
|
|
13472
13573
|
).split("\n").filter(Boolean);
|
|
13473
13574
|
targetFiles.push(...targetFileNames);
|
|
13474
|
-
|
|
13575
|
+
execSync3(`git fetch origin ${this.i18nBranchName}`, { stdio: "inherit" });
|
|
13475
13576
|
for (const file of targetFiles) {
|
|
13476
13577
|
try {
|
|
13477
|
-
|
|
13578
|
+
execSync3(`git checkout FETCH_HEAD -- ${file}`, { stdio: "inherit" });
|
|
13478
13579
|
} catch (error2) {
|
|
13479
13580
|
this.ora.warn(`Skipping non-existent file: ${file}`);
|
|
13480
13581
|
continue;
|
|
@@ -13485,8 +13586,8 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
13485
13586
|
this.ora.start("Checking for changes to commit");
|
|
13486
13587
|
const hasChanges = this.checkCommitableChanges();
|
|
13487
13588
|
if (hasChanges) {
|
|
13488
|
-
|
|
13489
|
-
|
|
13589
|
+
execSync3("git add .", { stdio: "inherit" });
|
|
13590
|
+
execSync3(
|
|
13490
13591
|
`git commit -m "chore: sync with ${this.platformKit.platformConfig.baseBranchName}" --no-verify`,
|
|
13491
13592
|
{
|
|
13492
13593
|
stdio: "inherit"
|
|
@@ -13518,18 +13619,18 @@ Hey team,
|
|
|
13518
13619
|
};
|
|
13519
13620
|
|
|
13520
13621
|
// src/cli/cmd/ci/platforms/bitbucket.ts
|
|
13521
|
-
import { execSync as
|
|
13622
|
+
import { execSync as execSync5 } from "child_process";
|
|
13522
13623
|
import bbLib from "bitbucket";
|
|
13523
13624
|
import Z8 from "zod";
|
|
13524
13625
|
|
|
13525
13626
|
// src/cli/cmd/ci/platforms/_base.ts
|
|
13526
|
-
import { execSync as
|
|
13627
|
+
import { execSync as execSync4 } from "child_process";
|
|
13527
13628
|
import Z7 from "zod";
|
|
13528
13629
|
var defaultMessage = "feat: update translations via @lingodotdev";
|
|
13529
13630
|
var PlatformKit = class {
|
|
13530
13631
|
gitConfig(token, repoUrl) {
|
|
13531
13632
|
if (token && repoUrl) {
|
|
13532
|
-
|
|
13633
|
+
execSync4(`git remote set-url origin ${repoUrl}`, {
|
|
13533
13634
|
stdio: "inherit"
|
|
13534
13635
|
});
|
|
13535
13636
|
}
|
|
@@ -13633,10 +13734,10 @@ var BitbucketPlatformKit = class extends PlatformKit {
|
|
|
13633
13734
|
});
|
|
13634
13735
|
}
|
|
13635
13736
|
async gitConfig() {
|
|
13636
|
-
|
|
13737
|
+
execSync5("git config --unset http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy", {
|
|
13637
13738
|
stdio: "inherit"
|
|
13638
13739
|
});
|
|
13639
|
-
|
|
13740
|
+
execSync5(
|
|
13640
13741
|
"git config http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy http://host.docker.internal:29418/",
|
|
13641
13742
|
{
|
|
13642
13743
|
stdio: "inherit"
|
|
@@ -14065,7 +14166,7 @@ var status_default = new Command20().command("status").description("Show the sta
|
|
|
14065
14166
|
ora.start("Validating localization configuration...");
|
|
14066
14167
|
validateParams2(i18nConfig, flags);
|
|
14067
14168
|
ora.succeed("Localization configuration is valid");
|
|
14068
|
-
trackEvent(authId
|
|
14169
|
+
trackEvent(authId, "cmd.status.start", {
|
|
14069
14170
|
i18nConfig,
|
|
14070
14171
|
flags
|
|
14071
14172
|
});
|
|
@@ -14452,7 +14553,7 @@ var status_default = new Command20().command("status").description("Show the sta
|
|
|
14452
14553
|
`\u2022 Try 'lingo.dev@latest i18n --locale ${targetLocales[0]}' to process just one language`
|
|
14453
14554
|
);
|
|
14454
14555
|
}
|
|
14455
|
-
trackEvent(authId
|
|
14556
|
+
trackEvent(authId, "cmd.status.success", {
|
|
14456
14557
|
i18nConfig,
|
|
14457
14558
|
flags,
|
|
14458
14559
|
totalSourceKeyCount,
|
|
@@ -14463,7 +14564,7 @@ var status_default = new Command20().command("status").description("Show the sta
|
|
|
14463
14564
|
exitGracefully();
|
|
14464
14565
|
} catch (error) {
|
|
14465
14566
|
ora.fail(error.message);
|
|
14466
|
-
trackEvent(authId
|
|
14567
|
+
trackEvent(authId, "cmd.status.error", {
|
|
14467
14568
|
flags,
|
|
14468
14569
|
error: error.message,
|
|
14469
14570
|
authenticated: !!authId
|
|
@@ -14605,7 +14706,7 @@ async function renderHero2() {
|
|
|
14605
14706
|
// package.json
|
|
14606
14707
|
var package_default = {
|
|
14607
14708
|
name: "lingo.dev",
|
|
14608
|
-
version: "0.117.
|
|
14709
|
+
version: "0.117.17",
|
|
14609
14710
|
description: "Lingo.dev CLI",
|
|
14610
14711
|
private: false,
|
|
14611
14712
|
repository: {
|